
Vuejs渡劫系列的首篇文章,主要针对一年多日常开发中的,对Vuejs的一些技术细节的总结,新手看了可保平安,老鸟大婶看了可温故知新!
从开始观望Vue 1.0到项目迁移到Vue 2.x,到现在项目改造成Vue-SPA已经有一年的时间,不得不说Vue带来了很多前所未有的新鲜感和卓越的开发效率,但Vue(或者说MVVM框架)总不像jQuery来的那样纯粹简单,因此,一些未知的新鲜感总会隐藏着未知的劫难(keng),因此该系列取名为 Vuejs渡劫———该系列不漫谈每个API,只是对博主开发过程中遇到问题和Vue学习需要注意的点进行简要描述。
下面的注意点,是本人日常工作遇到过的疏忽或者一些比较要注意的Vue细节,不一定是坑,但是总会需要值得注意。注意的点会根据项目的推进 不定期更新 喜欢的朋友们可以保持关注!
安装
谨慎使用命令行工具(CLI)
Vue-Cli是官方提供的命令行工具,个人不建议上手就用,因为其需要你对Node.js,Webpack等工具有相当一定程度的了解。个人先后使用过seajs/spm3,require.js,webpack 1.x等工具,但也无法说精通loaders的机制,而且CLI集成了Vue-loaders和其他loaders的依赖关系,错综复杂,新手可以通过script link的方式或者NPM的方式去使用:
script
<script type="text/javascript" src="https://unpkg.com/vue@2.4.2/dist/vue.js"></script>
NPM
npm install vue
全局 API
Vue.extend 创建“子类”
extend 是一个很实用的方法,尤其是在对.vue单文件进行unit-test(单元测试)的时候。由于单文件模式下,一般只会在 App.vue 的入口处对vue实例,各个子类的模块,通过import或者require的方式进行加载。
通过利用 Vue.extend 创建子类,并挂载到Dom元素上:
import Vue from 'vue'
import Hello from '@/components/Hello'
describe('Hello.vue', () => {
it('should render correct contents', () => {
const Constructor = Vue.extend(Hello)
const vm = new Constructor().$mount()
expect(vm.$el.querySelector('#J_main div').textContent)
.to.equal('Welcome to Your Vue.js App')
})
})
nextTick: DOM更新完成回调
有时候,我们调用的方法需要DOM落地之后才可以执行,但是我们并不知道更改了data上的数据之后,DOM什么时候才就绪,这个时候我们就需要用 Vue.nextTick 或 this.$nextTick,其中后者为实例对象上的方法。
该方法可以去处理数据变更后,执行的DOM操作,如chart的绘制,一些jQuery基于DOM的插件等,下面是一个数据变更后,c3.js画图的应用:
this.trendChart.status = 'hasData';
this.$nextTick(function() {
c3.generate({
bindto: '#J_trend',
size: {
height: 350
}
……
});
});
选项/数据
data选项的一些禁忌
data选项是Vue定义中的一个最为重要的部分,虽然data是看似是简单json对象,但在使用的过程依旧有些需要注意的地方:
单文件中的使用
值得注意的是,单文件中,data 严格要求是一个 function,一个返回JSON对象的函数;
data的hook处理
博主在做一款数据平台的产品过程中,每个页面都拥有相同的data属性,重复定义,不仅会导致代码量提高,同时在vue单文件中也不够直观,此时我们可以通过外部的hook函数,进行初始化,在对外导出:
import hook from '@/components/hook';
var opts = {
data: {
//your datas
},
...rest
};
opts = hook(opts);
export default opts;
不要对data使用箭头函数
如data: () => { return { a: this.myProp }})。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例(同理 methods 和 watch 的观察函数定义也是),this.myProp 将是 undefined
使用computed 获取vuex公共变量
在使用 vuex 对状态进行管理的时候,在获取state上的值时,请在 computed 选项中声明获取,否则数据同步会有问题:
computed :{
viewType () {
return this.$store.state.user.viewType
}
}
数组更新问题
由于Vue使用的是defineProperty的方式进行监测变化,因此Vue无法监测到数组以下的变动:
1.当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
2.当你修改数组的长度时,例如: vm.items.length = newLength
针对第一个问题,可以通过以下方式触发更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)
针对第二个问题,可以通过以下方式触发更新
example1.items.splice(newLength)
二维(N维)数组更新方式
如果我们需要更新一个二维数组的某个变量的值,如需要更新 items[i][j]数组下的name属性,我们需要把更改的 index 参考数组更新第一个问题的方式设置为最前面的维度数组索引,即
// Vue.set
let newVal = items[i][j];
newVal[i][j].name = "new";
Vue.set(example1.items, i, newVal);
对象更新问题
如题,博主说的并不是你的对象更新[窃笑],这里说的是Vue中data的一个对象更新需要注意的点:我们不能后续异步的建立新的对象属性,如我们data中,有个man对象只有 name 的属性:
man:{
name: "momo"
}
此时,如果我们需要添加一个age的属性,我们不能直接写 this.man.age = 26 而是需要通过 set方法进行增加监测对象:
Vue.set(vm.man, 'age', 26);
或
this.$set(this.man, 'age', 26);
除此以外,如果你执意要用 this.man.age = 26 这个方式更改,你可以通过提前配置这个属性为缺省值,如:
man:{
name: "momo",
age: ""
}
组件
组件props命名
HTML 特性是不区分大小写的。所以,当使用的不是字符串模板,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:
Vue.component('child', {
// camelCase in JavaScript
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<!-- kebab-case in HTML -->
<child my-message="hello!"></child>
单向数据流
Vue使用的是单向数据流,提倡 props down,event up方式,通过使用Props传递数据:
Vue.component('child', {
// 声明 props
props: ['message'],
// 就像 data 一样,prop 可以用在模板内
// 同样也可以在 vm 实例中像“this.message”这样使用
template: '<span>{{ message }}</span>'
})
<child message="hello!"></child>
子组件通过 $emit自定义方式,去唤起父组件变更数据:
this.$emit('say', message);
<child @say="toSay" message="hello!"></child>
通过 @say 对其自定义事件进行侦听,事件触发后,执行父组件的toSay()去驱动数据更新
methods:{
toSay () {
this.message = otherVal;
}
}
点击子组件触发方法
如你使用了vue-router,并希望在 <router-link></router-link> 被点击的时候,调用当前的方法
<router-link v-on:click.native="doSomething"></router-link>
指令
v-for多层循环的时候,注意对象和索引值的命名
如你写了一个三层循环的组件,第一层为(items,index)那么第二层为 (item, idex) 然后第三层为 (itm, idx),…… [这么长,我哭了T T]
要注意,每层的变量都是当前整个data的全局环境,因此每一层的对象和索引值都要有所不同,否则变量名被覆盖,就无法取到正确的对象或索引。
不要通过 v-model与 表单控件的checked属性绑定
如题,博主曾经通过v-model的值 true/false去控制checked切换, 这里已经做了很多次尝试,最后还是没有好的成效,最后通过模拟 CheckBox或者 radio的方式解决。
增加v-cloak指令,免除渲染过程出现 的出现
由于数值渲染会依赖Vuejs和其他组件加载的后,才会正确显示,才过程中,如果html页面中通过表达式的方式引用,网速过慢的情况下,可能会看到 的情况,可以参考官方写入一个 v-cloak 指令,并对指令增加属性样式:
[v-cloak] {
display: none;
}
<div v-cloak>
{{ message }}
</div>
Vue在数据准备完成后,会主动移除 v-cloak 这个指令(属性),数据就会在正确的时间被正确地显示了。
总结
由于博主人老了,脑瓜er不灵光了,有些遇到的坑被填过就忘了,后续想起来,或者遇到其他问题,会继续更新文章,也欢迎小伙伴或者大婶们,多多指正和关注后续的系列文章。