最近要求使用vue进行前后端分离开发微信公众号,不断摸索踩坑之后,总结出如下几点vue项目开发中常见的问题及解决办法。如果你是vue大佬,请忽略小弟的愚见^V^
===========================这是华丽丽的分割线~~=========================
例如商品列表页面前往商品详情页面,需要传一个商品id;
前往detail页面
c页面的路径为http://localhost:8080/#/detail?id=1,可以看到传了一个参数id=1,并且就算刷新页面id也还会存在。此时在c页面可以通过id来获取对应的详情数据,获取id的方式是this.$route.query.id
补充一下其他两种传参:
上面的这个报错大家都不会陌生,报错是说没有访问权限(跨域问题)。本地开发项目请求服务器接口的时候,因为客户端的同源策略,导致了跨域的问题。
vue-cli初始化的项目,在配置文件中提供了proxyTable来解决本地开发的跨域问题。config文件的index.js文件中,找到proxyTable选项,进行如下配置:
proxyTable: { // 用‘/api’开头,代理所有请求到目标服务器 '/api': { target: 'http://jsonplaceholder.typicode.com', // 接口域名 changeOrigin: true, // 是否启用跨域 pathRewrite: { // '^/api': '' } }}
例如请求接口:/api/posts/1 ==>http://jsonplaceholder.typicode.com/posts/1
这个时候就可以在本地环境请求后台接口了。
axios的封装,主要是用来帮我们进行请求的拦截和响应的拦截。
在请求的拦截中我们可以携带userToken,post请求头、qs对post提交数据的序列化等。
在响应的拦截中,我们可以进行根据状态码来进行错误的统一处理等等。
axios接口的统一管理,是做项目时必须的流程。这样可以方便我们管理我们的接口,在接口更新时我们不必再返回到我们的业务代码中去修改接口。
由于这里内容稍微多一些,日后放在另一篇文章,更新后这里会送上链接。
为什么要使用按需加载的方式而不是一次性全部引入,原因就不多说了。这里以vant的按需加载为例,演示vue中ui库怎样进行按需加载:
libraryDirectory { "plugins": [ // 这里是原来的代码部分 // ………… // 这里是要我们配置的代码 ["import", { "libraryName": "vant", "libraryDirectory": "es", "style": true } ] ] }
// 按需引入vant组件import { DatetimePicker, Button, List } from 'vant';
// 使用vant组件Vue.use(DatetimePicker) .use(Button) .use(List);
按钮
补充:出来vant库外,像antiUi、elementUi等,很多ui库都支持按需加载,可以去看文档,上面都会有提到。基本都是通过安装babel-plugin-import插件来支持按需加载的,使用方式与vant的如出一辙,可以去用一下。
我在a页面写一个定时,让他每秒钟打印一个1,然后跳转到b页面,此时可以看到,定时器依然在执行。这样是非常消耗性能的。如下图所示:
解决思路很简单:
首先我在data函数里面进行定义定时器名称:
data() { return { timer: null // 定时器名称 } },
然后这样使用定时器this.timer = setInterval(……………………)
最后在beforeDestroy()生命周期内清除定时器:
beforeDestroy() { clearInterval(this.timer); this.timer = null;}
我们在做手机端时,适配是必须要处理的一个问题。例如,我们处理适配的方案就是通过写一个rem.js,原理很简单,就是根据网页尺寸计算html的font-size大小,基本上小伙伴们都知道,这里直接附上代码,不多做介绍。
;(function(c,d){var e=document.documentElement||document.body,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;e.style.fontSize=(f>=750)?"100px":100*(f/750)+"px"};b();c.addEventListener(a,b,false)})(window);
这里说下怎么引入的问题,很简单。在main.js中,直接import './config/rem'导入即可。import的路径根据你的文件路径去填写。
在我们使用的很多ui库(vant、antiUi、elementUi等)中,都有轮播组件,对于普通的轮播效果足够了。但是,某些时候,我们的轮播效果可能比较炫,这时候ui库中的轮播可能就有些力不从心了。当然,如果技术和时间上都还可以的话,可以自己造个比较炫的轮子。
这里我说一下vue-awesome-swiper这个轮播组件,真的非常强大,基本可以满足我们的轮播需求。swiper相信很多人都用过,很好用,也很方便我们二次开发,定制我们需要的轮播效果。vue-awesome-swiper组件实质上给予swiper的,或者说就是能在vue中跑的swiper。下面说下怎么使用:
// 引入组件import 'swiper/dist/css/swiper.css' import { swiper, swiperSlide } from 'vue-awesome-swiper'// 在components中注册组件components: { swiper, swiperSlide}// template中使用轮播// ref是当前轮播// callback是回调// 更多参数用法,请参考文档// 参数要写在data中data() { return { // swiper轮播的参数 swiperOption: { // 滚动条 scrollbar: { el: '.swiper-scrollbar', }, // 上一张,下一张 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, // 其他参数………… } } }, 1 2 3 4 5 6 7
附上文档:npm文档,swiper3.0/4.0文档,更多用法,请参考文档说明。
项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。 而生成的.map后缀的文件,就可以像未加密的代码一样,准确的输出是哪一行哪一列有错可以通过设置来不生成该类文件。但是我们在生成环境是不需要.map文件的,所以可以在打包时不生成这些文件:在config/index.js文件中,设置productionSourceMap: false,就可以不生成.map文件
开发移动端项目,点击事件会有300ms延迟的问题。至于为什么会有这个问题,请自行百度即可。这里只说下常见的解决思路,不管vue项目还是jq项目,都可以使用fastClick解决。
安装 :
cnpm install fastclick -S
在main.js中引入和初始化:
import FastClick from 'fastclick'; // 引入插件FastClick.attach(document.body); // 使用 fastclick
export default { name: '', mixins: [], components: {}, props: {}, data() {}, computed: {}, watch: {}, created() {}, mounted() {}, destroyed() {}, methods: {}};
如果你是vue-cli初始化的项目,会默认安装webpack-bundle-analyzer插件,该插件可以帮助我们查看项目的体积结构对比和项目中用到的所有依赖。也可以直观看到各个模块体积在整个项目中的占比。很霸道有木有~~
npm run build --report // 直接运行,然后在浏览器打开http://127.0.0.1:8888/即可查看
记得运行的时候先把之前npm run dev开启的本地关掉
路由懒加载可以帮我们在进入首屏时不用加载过度的资源,从而减少首屏加载速度。
路由文件中,
非懒加载写法:
import Index from '@/page/index/index';export default new Router({ routes: [ { path: '/', name: 'Index', component: Index } ]})
路由懒加载写法:
export default new Router({ routes: [ { path: '/', name: 'Index', component: resolve => require(['@/view/index/index'], resolve) } ]})
spa这种单页应用,首屏由于一次性加载所有资源,所有首屏加载速度很慢。解决这个问题非常有效的手段之一就是前后端开启gizp(其他还有缓存、路由懒加载等等)。gizp其实就是帮我们减少文件体积,能压缩到30%左右,即100k的文件gizp后大约只有30k。
vue-cli初始化的项目中,是默认有此配置的,只需要开启即可。但是需要先安装插件:
cnpm i compression-webpack-plugin
然后在config/index.js中开启即可:
build: { ……………… productionGzip: true, // false不开启gizp,true开启 ………………}
现在打包的时候,除了会生成之前的文件,还是生成.gz结束的gzip过后的文件。具体实现就是如果客户端支持gzip,那么后台后返回gzip后的文件,如果不支持就返回正常没有gzip的文件。
**注意:这里前端进行的打包时的gzip,但是还需要后台服务器的配置。配置是比较简单的,配置几行代码就可以了,一般这个操作可以叫运维小哥哥小姐姐去搞一下,没有运维的让后台去帮忙配置。
这样一个场景:有三个页面,首页/或者搜索页,商品分类页面,商品详情页。我们希望从首页进入分类页面时,分类页面要刷新数据,从分类进入详情页再返回到分类页面时,我们不希望刷新,我们希望此时的分类页面能够缓存已加载的数据和自动保存用户上次浏览的位置。之前在百度搜索的基本都是keep-alive处理的,但是总有那么一些不完善,所以自己在总结了之后进行了如下的实践。
解决这种场景需求我们可以通过vue提供的keepAlive属性。这里直接送上另一篇处理这个问题的传送门吧
看评论提议: 这个传送的实践方案并不优,如果是pc其实无妨,如果是移动端,缓存组件就显得更重要了,我们只需要在进入组件的时候更新数据就可以了,可以使用activated钩子更新数据也可以通过路由传参监控路由更新数据
CSS的coped私有作用域和深度选择器
大家都知道当
编译后:
上述代码将会编译成:
.parent[data-v-f3f3eg9] .child { /* ... */ }
而对于less或者sass等预编译,是不支持>>>操作符的,可以使用/deep/来替换>>>操作符,例如:.parent /deep/ .child { /* ... */ }
==================================
后面会继续更新:
作者:chinaBerg 原文链接:https://juejin.im/post/5b174de8f265da6e410e0b4e 如有侵权请联系删除