关于Vue踩的坑及解决方案

关于Vue踩的坑及解决方案

Posted by Mr Kang on December 19, 2017

前言

关于Vue踩的坑及解决方案

采坑一:Vue.js导航栏切换问题

在单页应用中,由于页面切换不会导致浏览器重新加载页面,所以页面的标题是不会改变的,这时候就要通过Javascript去修改标题。这个操作本来是非常简单的,只需要修改「document.title」即可:

document.title = 'New title';

**然而,在iOS的微信和QQ中,这种方法可能无效,具体的现象就是:导航栏上的标题没有改变。这是iOS微信和QQ的bug,解决方法就是在修改「document.title」之后,用「iframe」发送一个请求(任意一个请求)。把相关的代码封装成函数:

function setTitle(title) {
    document.title = title;
    if (isIOS && (isInWeixin || isInQQ)) {
        let iframe = document.createElement('iframe');
        iframe.style.display = 'none';
        iframe.src = '/favicon.ico';
        iframe.onload = () => {
            setTimeout(() => {
                document.body.removeChild(iframe);
            }, 9);
        };
        document.body.appendChild(iframe);
    }
}

据说新版的微信和QQ已经修复了这个bug,但为了兼容旧版本,这段代码还是必须的。

采坑二:列表更新检测

1.2.1数组更新检测

以下摘自vue官网API

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

当你利用索引直接设置一个项时,例如:

vm.items[indexOfItem] = newValue

当你修改数组的长度时,例如:

vm.items.length = newLength

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

为了解决第二类问题,你可以使用 splice:

example1.items.splice(newLength)

触发视图更新的方法:

变异方法

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

vue提供的set方法

Vue.set( target, key, value )

2.1.2对象更新检测

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

解决方法:

vue提供的set方法

Vue.set( target, key, value )
Object.assign()
bject.assign({}, target, {key:value})

采坑三:页面刷新vuex被清空

这真的是遇到一个很坑的问题,同一个页面(router未改变),一旦刷新(刷新或深度刷新),存储的vuex就马上和你说拜拜

localStorage 网上推荐最多的方法就是用localStorage。但是我个人觉得不太合适,还得看项目吧。localStorage是永久存储的。

数据重新获取 我使用的方法是在需要某些数据之前先判断一下数据是否存在,如果不存在重新获取。

采坑四:nextTick适当使用

将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

简而言之,等待DOM更新之后再进行操作。

采坑五:异步问题

这个是一个亘古不变的话题。

请求后台数据异步,常不经意的带来了问题。(处理异步的方法就不详细描述了,网上一搜一大堆)

采坑六:组件之间的调用方式

父子组件

prop向下传递,事件向上传递 子组件添加ref属性,父组件可以获取到子组件的实例(不建议) 插槽slot 作用域插槽

非父子组件

使用状态管理 实例化一个公共vue实例

采坑七:计算属性设置值

计算属性是基于它们的依赖进行缓存的,一旦依赖发生变化,计算属性会重新计算

想要改变计算属性的值。要通过set方法去触发它所依赖的变量,(类似于触发它重新计算,单纯赋予一个新值,在取的时候也是不会被改变的)

采坑八:vue文件中内联样式中有无scoped属性的差别

有scoped属性: 当前仅当该vue文件可以使用这个样式。 无scoped属性: 影响其他文件

采坑九: v-for v-key

当 Vue.js 用v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):

采坑十: v-for 和 v-if

当它们处于同一节点,v-for的优先级比v-if更高。

采坑十一: js文件中引入的css不会自动加前缀

无论是开发环境还是生成环境都不会自动加前缀,因为vue-loader只管.vue文件里面的样式,没有自动执行autoprefixer loader

参考链接

2.优化 2.1.错误处理 错误处理很重要但是这是最容易让开发忽略的点。

2.1.1.请求接口错误 由于我的请求是使用axios插件或者fetch单独写在了一个js,可以对其进行响应拦截。一旦失败,或者后台报错,就进行响应的错误处理以及友好提示,也避免了重复的代码,提高可维护性

2.1.2.页面错误处理(404) nginx未匹配到路由走404路由 router.beforeEach是否匹配到响应的路由,否则走错误路由。 2.1.3 错误提示封装 将错误提示模块化,通过vuex来操作错误的显示以及信息等内容。

2.2.减少不必要的依赖包 性能优化是很重要的,特别是对于vue这种首屏加载时间长的。

例如有些项目用到了图表(echarts),可以选择加载依赖包,不用加载整个echarts库。

2.3.不发送多个相同的请求 不发送多个相同的请求,在点击触发请求的同时锁定请求,直至给出响应/错误解锁。