app
vue.config.js
文件。常见配置如下:const path = require(‘path‘)
module.exports = {
// 基本路径
publicPath: process.env.NODE_ENV === ‘production‘
? ‘/production-sub-path/‘
: ‘/‘,
// 输出文件目录
outputDir: process.env.NODE_ENV === ‘production‘ ? ‘dist‘ : ‘devdist‘,
// eslint-loader 是否在保存的时候检查
lintOnSave: true,
/**
1. webpack配置,see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
**/
chainWebpack: () => {
},
configureWebpack: config => {
if (process.env.NODE_ENV === ‘production‘) {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
config.resolve = { // 配置解析别名
extensions: [‘.js‘, ‘.vue‘],
alias: {
‘@‘: path.resolve(__dirname, ‘./src‘),
‘public‘: path.resolve(__dirname, ‘./public‘),
‘components‘: path.resolve(__dirname, ‘./src/components‘),
‘common‘: path.resolve(__dirname, ‘./src/common‘),
‘views‘: path.resolve(__dirname, ‘./src/views‘),
‘store‘: path.resolve(__dirname, ‘./src/store‘),
‘assets‘: path.resolve(__dirname, ‘./src/assets‘),
‘api‘: path.resolve(__dirname, ‘./src/api‘),
‘test‘: path.resolve(__dirname, ‘./src/test‘)
}
}
},
// 生产环境是否生成 sourceMap 文件
productionSourceMap: false,
// css相关配置
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {
stylus: {
// 全局导入stylus样式
data: `@import "~@/common/stylus/index.styl";`
}
},
// 启用 CSS modules for all css / pre-processor files.
modules: true
},
// use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores
parallel: require(‘os‘).cpus().length > 1,
/**
2. PWA 插件相关配置,see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
*/
pwa: {},
// webpack-dev-server 相关配置
devServer: {
open: false, // 编译完成是否打开网页
host: ‘0.0.0.0‘, // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
port: 8080, // 访问端口
https: false, // 编译失败时刷新页面
hot: true, // 开启热加载
hotOnly: false,
proxy: null, // 设置代理
overlay: { // 全屏模式下是否显示脚本错误
warnings: true,
errors: true
},
before: app => {
}
},
/**
3. 第三方插件配置
*/
pluginOptions: {}
}
上面一段配置只适用于自己。
src
下设置一个common
目录,然后把所有的css样式都放到里面。重置文件一般为reset.less
,全局样式文件一般为base.less
,字体及颜色目录文件一般为variable.less
,在项目中要使用到的一些特殊样式为mixin.styl
,字体图表样式为icon.less
,出口问文件为index.styl
。具体参考内容如下:index.styl文件
:
@import "./base"
@import "./reset"
@import "./icon"
@import "variable"
reset.styl
:
/*移动端css样式重置,如果要修改全局样式请在base.styl文件里面修改*/
html {
font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%
}
html, body {
-webkit-user-select: none;
user-select: none;
}
html, body, div, object, iframe, applet,
object, h1, h2, h3, h4, h5, h6, p, blockquote,
pre, address, dl, dt, dd, ol, ul, li, table,
caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, figure,
figcaption, footer, header, menu, nav, output, ruby,
section, summary, time, mark, audio, video, progress {
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline
}
a {
text-decoration: none;
-webkit-touch-callout: none;
background-color: transparent
}
li {
list-style: none
}
article, aside, details, figcaption, figure,
footer, header, main, menu, nav,
section, summary {
display: block
}
audio, canvas, progress, video {
display: inline-block
}
audio:not([controls]) {
display: none;
height: 0
}
[hidden], template {
display: none
}
a:active, a:hover {
outline: 0
}
abbr[title] {
border-bottom: 1px dotted
}
b, strong {
font-weight: bold
}
dfn {
font-style: italic
}
h1 {
font-size: 8.533vw;
margin: 2.859vw 0
}
small {
font-size: 80%
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline
}
sup {
top: -2.13vw;
bottom: -2.13vw
}
sub {
}
img {
border: 0;
-webkit-touch-callout: none;
}
svg:not(:root) {
overflow: hidden
}
figure {
margin: 4.2667vw 10.667vw
}
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0
}
pre {
overflow: auto
}
code, kbd, pre, samp {
font-family: monospace, monospace;
font-size: 4.267vw
}
a, button, input, optgroup, select, textarea {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
button, input, optgroup, select, textarea {
color: inherit;
font: inherit;
margin: 0;
-webkit-appearance: none;
outline: none;
line-height: normal
}
button {
overflow: visible
}
button, select {
text-transform: none
}
button, html input[type="button"], input[type="reset"], input[type="submit"] {
-webkit-appearance: button;
cursor: pointer
}
button[disabled], html input[disabled] {
cursor: default
}
button::-moz-focus-inner, input::-moz-focus-inner {
border: 0;
padding: 0
}
input {
line-height: normal
}
input[type="checkbox"], input[type="radio"] {
box-sizing: border-box;
padding: 0
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto
}
input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box
}
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none
}
fieldset {
border: 1px solid silver;
margin: 0 2px;
padding: 1.493vw 2.667vw 3.2vw
}
legend {
border: 0;
padding: 0
}
textarea {
overflow: auto
}
optgroup {
font-weight: bold
}
table {
border-collapse: collapse;
border-spacing: 0
}
td, th {
padding: 0
}
base.styl文件
:
// 整体样式
body, html
line-height: 1
font-weight: 200
font-family: ‘PingFang SC‘, ‘STHeitiSC-Light‘, ‘Helvetica-Light‘, arial, sans-serif
// 清除浮动
.clearfix
display: inline-block
&:after
display: block
content: "."
height: 0
line-height: 0
clear: both
visibility: hidden
// 图片处理1.5倍像素屏幕1px处理与2倍像素屏幕1px处理
@media (-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)
.border-1px
&::after
-webkit-transform: scaleY(0.7)
transform: scaleY(0.7)
@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2)
.border-1px
&::after
-webkit-transform: scaleY(0.5)
transform: scaleY(0.5)
variable.styl文件
:
// 颜色定义规范
$color-background = #222
$color-background-d = rgba(0, 0, 0, 0.3)
$color-highlight-background = #333
$color-dialog-background = #666
$color-theme = #ffcd32
$color-theme-d = rgba(255, 205, 49, 0.5)
$color-sub-theme = #d93f30
$color-text = #fff
$color-text-d = rgba(255, 255, 255, 0.3)
$color-text-l = rgba(255, 255, 255, 0.5)
$color-text-ll = rgba(255, 255, 255, 0.8)
//字体定义规范
$font-size-10 = 2.667vw
$font-size-12 = 3.2vw
$font-size-14 = 3.733vw
$font-size-16 = 4.267vw
$font-size-18 = 4.8vw
$font-size-20 = 5.33vw
$font-size-22 = 5.867vw
mixin.styl文件
:
// 上边框1px
border-1px($color)
position: relative
&:after
display: block
position: absolute
left: 0
bottom: 0
width: 100%
border-top: 1px solid $color
content: ‘ ‘
// 没有边框
border-none()
&:after
display: none
// 图片,3倍和2倍
bg-image($url)
background-image: url($url + "@2x.png")
@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3)
background-image: url($url + "@3x.png")
值得说明的是字体图标,项目一般会使用iconfont字体图标
目录结构
由于很少使用到vuex
模块,为了更加的熟悉vuex
模块,在此记录:
index.js
import Vue from ‘vue‘
import Vuex from ‘vuex‘
import * as actions from ‘./actions‘
import * as getters from ‘./getters‘
import mutations from ‘./mutations‘
import states from ‘./states‘
Vue.use(Vuex)
export default new Vue.Store({
actions,
getters,
state,
mutations
})
2.state.js
const state = {
name:‘‘
}
export default states
3.mutation-types.js
export const SET_NAME = set_name // 修改名字信息(请加上注释)
4.mutations.js
import * as type from ‘./mutation-types‘
const mutations = {
[type.SET_NAME](state,name){
state.name = name
}
}
export mutations
5.getters.js
export const name = state => state.name
6.actions.js
import * as type from ‘./mutation-types‘
export const changeName = ({commit},{newName}){
commit(types.SET_NAME, newName)
}
axiox
的封装可以分为三步,个人喜欢在项目目录文件夹下建立一个api
文件来专门存放关于api
接口的一些东西http.js
用来专门封装 axios
的接口设置,一般会和vue-axios使用
http.js文件
import axios from ‘axios‘
import vueAxios from ‘vue-axios‘
import Vue from ‘vue‘
import QS from ‘qs‘
Vue.use(vueAxios,axios)
// axios 环境设置
if(process.env.NODE_ENV === ‘production‘){
axios.defaults.baseURL= ‘http://prouction.com‘
}else if(process.env.NODE_ENV === ‘development‘){
axios.defaults.baseURL = ‘http://development.com‘
}else if(process.env.NODE_ENV === ‘debug‘){
axios.defaults.baseURL = ‘http://debug.com‘
}
// axios请求超时
axios.defaults.timeout = 10000
// post请求头
axios.defaults.headers = {
‘X-Requested-With‘: ‘XMLHttpRequest‘,
‘Content-Type‘: ‘application/x-www-form-urlencoded;charset=UTF-8‘
}
// 请求拦截器
axios.interceptors.request.use(
config=>{
// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
// const token = store.state.user.token
// token && (config.headers.Authorization = `Bearer ${token}`)
config.data = QS.stringify(config.data)
return config
},
error => {
return Promise.error(error)
})
// 相应拦截器
let errorHandle = (status, other) => {
if (status) {
switch (status) {
/**
* 401: 未登录
* 未登录则跳转登录页面,并携带当前页面的路径
*在登录成功后返回当前页面,这一步需要在登录页操作。
*/
case 401:
// tip(‘未登录,请先登录‘)
break
/**
* 403 token过期,登录过期对用户进行提示,清除本地token和清空vuex中token对象,跳转登录页面
*/
case 403:
// tip(‘登录过期,请重新登录‘)
// setTimeout(() => {
// logout()
// }, 1000)
break
// 404请求不存在
case 404:
// tip(‘请求的资源不存在‘)
break
// 其他错误,直接抛出错误提示
default:
// tip({
// message: error.response.data.message,
// duration: 1500, // 持续时间
// forbidClick: true
// })
console.log(other)
break
}
}
}
axios.interceptors.response.use(
// 拿到数据200
res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
// 未拿到,非200
error => {
if (error.response === undefined) {
console.log(‘response:‘ + error.message)
return Promise.reject(error)
// tip(‘后台错误,请求undfined‘)
}
errorHandle(error.response.status, error.response.data.message)
return Promise.reject(error.response)
}
)
/**
* 封装接口调用方法
* @param url:地址
* @param data:传入参数
* @param type:类型(仅限于get/post)
* @returns {Promise<any>}
* @constructor
*/
export function Axios (url, data = {}, type = ‘GET‘) {
return new Promise((resolve, reject) => {
// 执行异步请求
let promise
if (type === ‘GET‘) {
// 准备url的query参数数据
let dataStr = ‘‘ // 数据拼接字符串
Object.keys(data).forEach(key => {
dataStr += key + ‘=‘ + data[key] + ‘&‘
})
if (dataStr !== ‘‘) {
dataStr = dataStr.substring(0, dataStr.lastIndexOf(‘&‘))
url = url + ‘?‘ + dataStr
}
// get请求
promise = axios.get(url)
} else {
// 发送post请求
promise = axios.post(url, data)
}
promise.then(response => {
// 成功拿到response的data
resolve(response.data)
}).catch(error => {
reject(console.log(error))
})
})
}
base.js
里面存放的是api接口模块,所有的接口都存放在里面:base.js文件
let baseURL = ‘10.10.21.86‘
export nameURL = baseURL + ‘/name‘
export let loginURL = baseURL + ‘/account/login‘
export let guestURL = baseURL + ‘/account/guest‘
export let regURL = baseURL + ‘/account/reg‘
export let accountURL = baseURL + ‘/home/account‘
export let kefuURL = baseURL + ‘/home/getkefu‘
api.js
文件是获取数据的接口方法模块:
api.js文件
import {Axios} from ‘./http‘
import * as url from ‘./base‘
esport const getName = ({data})=>Axios(url.nameURL,{data},‘POST‘)
在 vuex
的 actions.js
文件里面可以直接调用方法从而异步获取数据的
原文:https://www.cnblogs.com/ginkgo-leaves/p/10751910.html