项目总结
项目总结
app
技术栈
vue+vuex+vue-cli@3.0+stylus+axios+vant-ui
一些基本的配置
- vue-cli3.0中简化了相应的配置文件,使得项目文件相对而言更加的清爽,配置也变得相对简单。在项目的目录文件下创建
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分离插件 ExtractTextPluginextract: 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 coresparallel: 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: {}}
上面一段配置只适用于自己。
- css在手机端的样式
根据个人习惯设置项目目录:个人会在项目的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, htmlline-height: 1font-weight: 200font-family: 'PingFang SC', 'STHeitiSC-Light', 'Helvetica-Light', arial, sans-serif// 清除浮动.clearfixdisplay: inline-block&:afterdisplay: blockcontent: "."height: 0line-height: 0clear: bothvisibility: 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文件:
// 上边框1pxborder-1px($color)position: relative&:afterdisplay: blockposition: absoluteleft: 0bottom: 0width: 100%border-top: 1px solid $colorcontent: ' '// 没有边框border-none()&:afterdisplay: 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模块,为了更加的熟悉vuex模块,在此记录:index.jsimport 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.jsconst state = {name:''}export default states
3.
mutation-types.jsexport const SET_NAME = set_name // 修改名字信息(请加上注释)
4.
mutations.jsimport * as type from './mutation-types'const mutations = {[type.SET_NAME](state,name){state.name = name}}export mutations
5.
getters.jsexport const name = state => state.name
6.
actions.jsimport * as type from './mutation-types'export const changeName = ({commit},{newName}){commit(types.SET_NAME, newName)}
axiox封装
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(// 拿到数据200res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),// 未拿到,非200error => {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 promiseif (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的dataresolve(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 文件里面可以直接调用方法从而异步获取数据的

浙公网安备 33010602011771号