vue.js 2.0 项目开发小结
2019-01-10 15:35
801 查看
项目架构
项目目录
[code]├── build ├── config ├── dist │ └── static │ ├── css │ ├── fonts │ ├── images │ ├── js │ └── lib ├── src │ ├── api │ ├── assets │ │ ├── global │ │ └── images │ │ └── footer │ ├── components │ │ ├── common │ │ ├── news │ │ └── profile │ │ └── charge │ ├── config │ ├── mixin │ ├── router │ ├── service │ ├── store │ └── util └── static ├── images └── lib
项目目录是采用
vue-cli自动生成,其它按需自己新建就好了。
开发实践
动态修改 document title
在不同的路由页面,我们需要动态的修改文档标题,可以将每个页面的标题配置在路由元信息
meta里面带上,然后在
router.beforeEach钩子函数中修改:
[code]import Vue from 'vue'; import Router from 'vue-router'; Vue.use(Router); const router = new Router({ mode: 'history', routes: [ { path: '/', component: Index, meta: { title: '推荐产品得丰厚奖金' } }, { path: '/news', component: News, meta: { title: '公告列表' }, children: [ { path: '', redirect: 'list' }, { path: 'list', component: NewsList }, { path: 'detail/:newsId', component: NewsDetail, meta: { title: '公告详情' } } ] }, { path: '/guide', component: GuideProtocol, meta: { title: '新手指南' } } ] }); router.beforeEach((to, from, next) => { let documentTitle = '商城会员平台'; // path 是多级的,遍历 to.matched.forEach((path) => { if (path.meta.title) { documentTitle += ` - ${path.meta.title}`; } }); document.title = documentTitle; next(); });
Event Bus 使用场景
我们在项目中引入了
vuex,通常情况下是不需要使用
eventbus的,但是有一种情况下我们需要使用它,那就是在路由钩子函数内部的时,在项目中,我们需要在
beforeEnter路由钩子里面对外抛出事件,在这个钩子函数中我们无法去到
this对象。
[code]beforeEnter: (to, from, next) => { const userInfo = localStorage.getItem(userFlag); if (isPrivateMode()) { EventBus.$emit('get-localdata-error'); next(false); return; } })
在
App.vue的
mouted方法中监听这个事件
[code]EventBus.$on('get-localdata-error', () => { this.$alert('请勿使用无痕模式浏览'); });
自定义指令实现埋点数据统计
在项目中通常需要做数据埋点,这个时候,使用自定义指令将会变非常简单
在项目入口文件
main.js中配置我们的自定义指令
[code]// 坑位埋点指令 Vue.directive('stat', { bind(el, binding) { el.addEventListener('click', () => { const data = binding.value; let prefix = 'store'; if (OS.isAndroid || OS.isPhone) { prefix = 'mall'; } analytics.request({ ty: `${prefix}_${data.type}`, dc: data.desc || '' }, 'n'); }, false); } });
在组件中使用我们的自定义指令
使用过滤器实现展示信息格式化
如下图中奖金数据信息,我们需要将后台返回的奖金格式化为带两位小数点的格式,同时,如果返回的金额是区间类型,需要额外加上 起 字和 ¥ 金额符号
在入口文件
main.js中配置我们自定义的过滤器
[code]Vue.filter('money', (value, config = { unit: '¥', fixed: 2 }) => { const moneyStr = `${value}`; if (moneyStr.indexOf('-') > -1) { const scope = moneyStr.split('-'); return `${config.unit}${parseFloat(scope[0]).toFixed(config.fixed).toString()} 起`; } else if (value === 0) { return value; } return `${config.unit}${parseFloat(moneyStr).toFixed(config.fixed).toString()}`; }); 在组件中使用: <p class="price">{{detail.priceScope | money}}</p> <div :class="{singleWrapper: isMobile}"> <p class="rate">比率:{{detail.commissionRateScope}}%</p> <p class="income">奖金:{{detail.expectedIncome | money}}</p> </div> axios 使用配置 在项目中,我们使用了 axios 做接口请求 在项目中全局配置 /api/common.js import axios from 'axios'; import qs from 'qs'; import store from '../store'; // 全局默认配置 // 设置 POST 请求头 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 配置 CORS 跨域 axios.defaults.withCredentials = true; axios.defaults.crossDomain = true; // 请求发起前拦截器 axios.interceptors.request.use((config) => { // 全局 loading 状态,触发 loading 效果 store.dispatch('updateLoadingStatus', { isLoading: true }); // POST 请求参数处理成 axios post 方法所需的格式 if (config.method === 'post') { config.data = qs.stringify(config.data); } // 这句不能省,不然后面的请求就无法成功发起,因为读不到配置参数 return config; }, () => { // 异常处理 store.dispatch('updateLoadingStatus', { isLoading: false }); }); // 响应拦截 axios.interceptors.response.use((response) => { // 关闭 loading 效果 store.dispatch('updateLoadingStatus', { isLoading: false }); // 全局登录过滤,如果没有登录,直接跳转到登录 URL if (response.data.code === 300) { // 未登录 window.location.href = getLoginUrl(); return false; } // 这里返回的 response.data 是被 axios 包装过的一成,所以在这里抽取出来 return response.data; }, (error) => { store.dispatch('updateLoadingStatus', { isLoading: false }); return Promise.reject(error); }); // 导出 export default axios;
然后我们在接口中使用就方便很多了
/api/xxx.js
[code]import axios from './common'; const baseURL = '/api/profile'; const USER_BASE_INFO = `${baseURL}/getUserBaseInfo.json`; const UPDATE_USER_INFO = `${baseURL}/saveUserInfo.json`; // 更新用户实名认证信息 const updateUserInfo = userinfo => axios.post(UPDATE_USER_INFO, userinfo); // 获取用户基础信息 const getUserBaseInfo = () => axios.get(USER_BASE_INFO);
vuex 状态在响应式页面中的妙用
由于项目是响应式页面,PC 端和移动端在表现成有很多不一致的地方,有时候单单通过 CSS 无法实现交互,这个时候,我们的
vuex状态就派上用场了,
我们一开始在
App.vue里面监听了页面的
resize事件,动态的更新
vuex里面
isMobile的状态值
[code]window.onresize = throttle(() => { this.updatePlatformStatus({ isMobile: isMobile() }); }, 500);
然后,我们在组件层,就能响应式的渲染不同的
dom结构了。其中最常见的是 PC 端和移动端加载的图片需要不同的规格的,这个时候我们可以这个做
[code]methods: { loadImgAssets(name, suffix = '.jpg 24000 ') { return require(`../assets/images/${name}${this.isMobile ? '-mobile' : ''}${suffix}`); }, } <img class="feed-back" :src="loadImgAssets('feed-back')" <img v-lazy="{src: isMobile ? detail.imgUrlMobile : detail.imgUrlPc, loading: placeholder}"> // 动态渲染不同规格的 dislog <el-dialog :visible.sync="dialogVisible" :size="isMobile ? 'full' : 'tiny'" top="30%" custom-class="unCertification-dialog"> </el-dialog>
下图分别是 PC 端和移动短的表现形式,然后配合 CSS 媒体查询实现各种布局
开发相关配置
反向代理
在项目目录的
config文件下面的
index.js配置我们的本地反向代理和端口信息
[code]dev: { env: require('./dev.env'), port: 80, autoOpenBrowser: true, assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: { '/api/profile': { target: '[真实接口地址]:[端口号]', // 例如: http://api.xxx.com changeOrigin: true, pathRewrite: { '^/api/profile': '/profile' } } ... },
然后我们调用接口的形式就会变成如下映射,当我们调用
/api/profile/xxxx的时候,其实是调用了
[真实接口地址]/profile/xxxx
[code]/api/profile/xxxx => [真实接口地址]/profile/xxxx
nginx 配置
[code]upstream api.xxx.com { #ip_hash; server [接口服务器 ip 地址]:[端口]; } server { ... location ^~ /api/profile { index index.php index.html index.html; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://api.xxx.com; rewrite ^/api/profile/(.*)$ /profile/$1 break; } ... }
线上部署
如果路由使用的是
history模式的话,需要在
nginx里面配置将所有的请求到转发到
index.html去
在
nginx.conf或者对应的站点
vhost文件下面配置
[code]location / { try_files $uri $uri/ /index.html; }
优化
开启静态资源长缓存
[code]location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|woff|ttf|eot|svg)$ { expires 1y; } location ~ .*\.(js|css)$ { expires 1y; }
开启静态资源 gzip 压缩
开启了 gzip 压缩之后,页面资源请求大小将大大减小,如下图所示,表示已经开启了
gzip压缩
相关文章推荐
- 20171102vue.js2.0:搭建开发环境及构建项目
- vue.js2.0实战:搭建开发环境及构建项目
- Vue项目开发中webpack样式,图片,js,html文件安装命令操作。
- 如何Vue-cli开始使用在Vue.js项目中启动TDD(测试驱动开发)
- 2018年基于 Vue.js 2.0 的 UI 组件库快速开发一个 Vue.js Web 应用 Element UI
- Vue.js 2.0和Cordova开发webApp环境搭建方法
- 如何用Vue-cli在Vue.js项目中启动TDD(测试驱动开发)
- 2019最新 基于 Vue.js 2.0 的 UI 组件库快速开发一个 Vue.js Web
- vue2.0项目 calendar.js(日历组件封装)
- vue.js2.0开发中的几个技巧
- vue.js开发外卖App项目的组件传值总结(七)
- vue2.0 使用vue-cli搭建的项目如何在index.html里引入静态css和js
- VUE2.0的简单入门(一)-安装node.js环境搭建与项目构建
- vue.js开发外卖App项目的vue-resource总结(六)
- 使用 Vue.js 2.0 框架开发和运行
- vue2.0新手填坑攻略之使用vue-cli搭建vue项目开发环境到项目发布
- vue.js开发外卖App项目的组件拆分总结(五)
- Vue.js2.0中的变化小结
- Vue.js 2.0和Cordova开发webApp环境搭建
- 如何Vue-cli开始使用在Vue.js项目中启动TDD(测试驱动开发)