1.只有当vue实例被创建时data中存在的属性才是响应式的:
如果你知道你会在晚些时候需要一个属性,但是一开始它为空或不存在,那么你仅需要设置一些初始值。
2.不要在选项属性或回调上使用箭头函数:
比如:
created: () => console.log(this.a)或
vm.$watch('a', newValue => this.myMethod())。
因为箭头函数是和父级上下文绑定在一起的,this不会是如你所预期的 Vue 实例,经常导致Uncaught TypeError: Cannot read property of undefined或Uncaught TypeError: this.myMethod is not a function之类的错误。
3.计算属性:computed
计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。下面的计算属性将不再更新,因为Date.now()不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
注:计算属性默认只有getter,需要时可以提供一个setter.
computed: {
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName
},
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
现在再运行vm.fullName = 'John Doe'时,setter 会被调用,vm.firstName和vm.lastName也会相应地被更新。
4.侦听属性:watch
当你有一些数据需要随着其它数据变动而变动时,你很容易滥用watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的watch回调。
// 使用watch
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
// 使用computed
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过watch选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
Ask a yes/no question:
{{ answer }}
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
methods: {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识
getAnswer: _.debounce(
function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
},
// 这是我们为判定用户停止输入等待的毫秒数
500
)
}
})
5.v-bind:class和v-bind:style的数组语法:
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
渲染为:
------------------------------------------------------------------------------------
data: {
baseStyles:{color:'red'},
overridingStyles:{font-size:'16px'}
}
渲染为:
注:当v-bind:style使用需要添加浏览器引擎前缀的 CSS 属性时,如transform,Vue.js 会自动侦测并添加相应的前缀。
6.v-if VS v-show
条件渲染v-if:
在template元素上使用v-if可以条件渲染(切换)多个元素。
注:v-else元素必须紧跟在带v-if或者v-else-if的元素的后面,否则它将不会被识别。
条件展示v-show:
v-show的元素始终会被渲染并保留在 DOM 中。v-show只是简单地切换元素的 CSS 属性display。
注:v-show不支持元素,也不支持v-else。
对比:v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
7.key
在v-if中的使用:
vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。例如,如果你允许用户在不同的登录方式之间切换:
Username
在上面的代码中切换loginType将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,不会被替换掉——仅仅是替换了它的placeholder。
Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的key属性即可:
Username
现在,每次切换时,输入框都将被重新渲染。元素仍然会被高效地复用,因为它们没有添加key属性。
在v-for中的使用:
当 Vue.js 用v-for正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一key属性。理想的key值是每项都有的且唯一的 id。这个特殊的属性相当于 Vue 1.x 的track-by,但它的工作方式类似于一个属性,所以你需要用v-bind来绑定动态值 (在这里使用简写):
建议尽可能在使用v-for时提供key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
8.数组的更新检测:
变异方法:
会改变原始数组,Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。
非变异方法:
不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
注:由于 JavaScript 的限制,Vue 不能检测以下变动的数组:当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
解决问题1:
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue) // vm.$set是Vue.set方法的一个别名
vm.items.splice(indexOfItem, 1, newValue)
解决问题2:
vm.items.splice(newLength)
注:由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。但是,可以使用Vue.set(object, key, value)方法向嵌套对象添加响应式属性。
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
可以添加一个新的age属性到嵌套的userProfile对象:
Vue.set(vm.userProfile, 'age', 27)或vm.$set(vm.userProfile, 'age', 27)
有时你可能需要为已有对象赋予多个新属性,比如使用Object.assign()或_.extend()。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,如下:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
其他:
可以利用带有v-for的渲染多个元素。
当v-for和v-if处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用。
如果你的目的是有条件地跳过循环的执行,那么可以将v-if置于外层元素 (或
9.事件处理:
v-on可以接收一个需要调用的方法名称。
Greet
也可以在内联 JavaScript 语句中调用方法,要在内联语句处理器中访问原始的 DOM 事件,可以用特殊变量$event把它传入方法。
Submit
注:
像其它只能对原生的 DOM 事件起作用的修饰符,.once修饰符还能被用到自定义的组件事件上。
不要把.passive和.prevent一起使用,因为.prevent将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive会告诉浏览器你不想阻止事件的默认行为。
系统修饰键:.ctrl,.shift,.meta,.alt。修饰键与常规按键不同,在和keyup事件一起用时,事件触发时修饰键必须处于按下状态。
.exact修饰符允许你控制由精确的系统修饰符组合触发的事件。
10.表单输入绑定
复选框:
单个复选框绑定到布尔值,多个复选框绑定到数组。
单选按钮:
绑定到被选中的按钮的value。
下拉列表:
多选时绑定到数组。
11.组件:
组件是可复用的 Vue 实例,它们与new Vue接收相同的选项,例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。
1.注册组件:
// 全局注册,全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,
// 也包括其组件树中的所有子组件的模板中。
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: 'You clicked me {{ count }} times.'
})
注:
一个组件的data选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。
2.通过prop向子组件传递数据:
prop:Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的
时候,它就变成了那个组件实例的一个属性。
Vue.component('blog-post', {
props: ['title'],
template: '
{{ title }}
'})
一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:
我们可以使用v-bind来动态传递 prop:
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' },
]
}
})
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
>
3.单个根元素:每个组件必须只有一个根元素。
4.通过事件向父级组件发送消息:我们可以调用内建的ef="https://cn.vuejs.org/v2/api/#实例方法-事件">$emit方法并传入事件的名字,来向父级组件触发一个事件。
Enlarge text
然后我们可以用v-on在博文组件上监听这个事件,就像监听一个原生 DOM 事件一样:
v-on:enlarge-text="postFontSize += $event"
>
有的时候用一个事件来抛出一个特定的值是非常有用的,可以使用$emit的第二个参数来提供这个值,在父级组件监听这个事件的时候,我们可以通过$event访问到被抛出的这个值,如上。
如果这个事件处理函数是一个方法,这个值会作为第一个参数传入该方法。如下:
v-on:enlarge-text="onEnlargeText"
>
methods: {
onEnlargeText: function (enlargeAmount) {
this.postFontSize += enlargeAmount
}
}
5.在自定义组件上使用v-model:
首先,下面两种写法是等价的:
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
但用在自定义组件上时,v-model会是这样:
v-bind:value="searchText"
v-on:input="searchText = $event"
>
为了使得该组件正常工作,该组件内的input必须:将其 value 特性绑定到一个名叫 value 的 prop 上
在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('custom-input',{
props:['value'],
template:
`
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
});
6.通过插槽分发内容:
Something bad happened.
Vue.component('alert-box', {
template: `
Error!
`
})
7.解析dom模板时的注意事项:
有些 HTML 元素,诸如
- 、
- 、
特殊的is特性给了我们一个变通的办法:
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的: