Vue.js 组件非常类似于自定义元素。有几个关键的不同:
①Vue.js 组件不需要任何补丁,并且在所有支持的浏览器(IE9 及更高版本)之下表现一致。Vue.js 组件也可以放在原生自定义元素之内
②Vue.js 组件提供了原生自定义元素所不具备的一些重要功能,比如组件间的数据流,自定义事件系统,以及动态的、带特效的组件替换
通过构造函数Vue创建实例化Vue对象
var vm = new Vue({
// 选项
})
或者
扩展 Vue 构造器
var MyComponent = Vue.extend({
// 扩展选项
})
// 所有的 `MyComponent` 实例都将以预定义的扩展选项被创建
var myComponentInstance = new MyComponent()
在实例化 Vue 时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项。
所有的 Vue.js 组件其实都是被扩展的 Vue 实例 -->因为扩展出来的Vue实例都会被继承然后可以创建组件
只有这些被代理的属性(data对象中的属性)是响应的
注意,不要在实例属性或者回调函数中(如vm.$watch('a', newVal => this.myMethod()))使用箭头函数。因为箭头函数绑定父上下文,所以 this 不会像预想的一样是 Vue 实例,而是 this.myMethod 未被定义。
在实例生命周期的不同阶段调用,如 mounted、 updated、destroyed、created 。钩子的 this 指向调用它的 Vue 实例
Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。在底层的实现上, Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。
使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。当然要注意其他数据是否绑定在上面,要是由数据也会影响的。
双大括号会将数据解释为纯文本,而非 HTML 。为了输出真正的 HTML ,你需要使用v-html 指令
javascript表达式被{{}}包起来会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式
指令(Directives)是带有 v- 前缀的特殊属性。指令属性的值预期是单一 JavaScript 表达式。指令的职责就是当其表达式的值改变时相应地将某些行为应用到 DOM 上。 v-if 指令将根据表达式 seen 的值的真假来移除/插入 <p> 元素。<p v-if="seen">Now you see me</p>
v-bind 缩写 <a v-bind:href="url"></a> <==> <a :href="url"></a>
v-on 缩写 <a v-on:click="doSomething"></a> <==> <a @click="doSomething"></a>
计算属性(定义一个属性来获取某个值)和method中定义相同函数名得到效果一样。不同的是计算属性是基于它的依赖缓存。计算属性只有在它的相关依赖发生改变时才会重新取值。相比而言,每当重新渲染的时候,method 调用总会执行函数。
Vue.js 提供了一个方法 $watch ,它用于观察 Vue 实例上的数据变动。
在v-bind 用于 class 和 style 时, Vue.js 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。
v-if 是一个指令,只能控制一组元素。那么要控制多组呢?把一个 <template> 元素当做包装元素,最终的渲染结果不会包含该元素
v-else 元素必须紧跟在 v-if 或 v-show 元素的后面——否则它不能被识别。
v-show与v-if大体一样,不同的是有 v-show 的元素会始终渲染并保持在 DOM 中。v-show 是简单的切换元素的 CSS 属性 display 。注意 v-show 不支持 <template> 语法。
v-if vs. v-show探讨
v-if 是真实的条件渲染,因为它会确保条件块在切换当中适当地销毁与重建条件块内的事件监听器和子组件。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——在条件第一次变为真时才开始局部编译(编译会被缓存起来)。
相比之下, v-show 简单得多——元素始终被编译并保留,只是简单地基于 CSS 切换。
一般来说, v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换使用 v-show 较好,如果在运行时条件不大可能改变则使用 v-if 较好。
用 v-for 指令根据一组数组的选项列表进行渲染。 v-for 指令需要以item in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名。
v-for 指令需要以(item,index) in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名。index指数组的下标
可以用带有 v-for 的 <template> 标签来渲染多个元素块。
自定义组件如果单单靠用 v-for是不能自动传递数据到组件里,因为组件有自己独立的作用域。为了传递迭代数据到组件里,我们要用 props
<my-component v-for="item in items"></my-component>
不自动注入 item 到组件里的原因是,因为这使得组件会紧密耦合到 v-for 如何运作。
数组的变异方法
push() 、pop()、 shift()、 unshift() 、splice() 、sort() 、reverse()
有非变异(non-mutating method)方法
filter(), concat(), slice()
数组的变异方法会改变被这些方法调用的原始数组。
非变异(non-mutating method)方法这些不会改变原始数组,但总是返回一个新数组
注意事项
由于 JavaScript 的限制, Vue 不能检测以下变动的数组(不会触发响应式的更改数据):
①当你直接设置一个项的索引时,例如: vm.items[indexOfItem] = newValue
②当你修改数组的长度时,例如: vm.items.length = newLength
第一的解决办法:
// Vue.set(实例对象.数组名,修改的下标,修改的新值)
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice 实例对象.数组名.splice(修改的下标,1,修改的新值)
example1.items.splice(indexOfItem, 1, newValue)
第二的解决办法:
example1.items.splice(newLength)
事件处理
在Vue实例中this代表这个Vue实例,event代表原生DOM事件
有时也需要在内联语句处理器中访问原生 DOM 事件。可以用特殊变量 $event 把它传入方法
preventDefault方法是取消事件的默认动作。
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。-->也就是说methods属性中处理的是数据逻辑,DOM事件处理的换其他处
事件修饰符
Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。有如下:
.stop 、.prevent、 .capture 、.self
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
按键修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符 如:
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">
Vue 为最常用的按键提供了别名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
全部的按键别名:
enter、 tab 、delete (捕获 “删除” 和 “退格” 键)、 esc 、space、 up 、down 、left、 right
可以通过全局 config.keyCodes 对象自定义按键修饰符别名:// 可以使用 v-on:keyup.f1Vue.config.keyCodes.f1 = 112
为什么在 HTML 中监听事件?
事件监听的方式违背了关注点分离(separation of concern)传统理念。不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:
①扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
②因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
③当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
表单控件绑定
用 v-model 指令在表单控件元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖,它负责监听用户的输入事件以更新数据,并特别处理一些极端的例子。
v-model 并不关心表单控件初始化所生成的值。因为它会选择 Vue 实例数据来作为具体的值。/*我认为:v-model绑定表单元素所属类型的默认值*/
<!-- v-model绑定的属性selected_option在此例子中一开始可以给一个初始值(一般为option选项的第一项):{number:123},或者给一个null值。每当点击选项时其绑定(v-bind)的属性value会传到父级中的v-model进行双向绑定达到联动 -->
<select v-model="selected_option">
<option v-bind:value="{ number: 123 }">123</option>
<option v-bind:value="{ number: 345 }">345</option>
<option v-bind:value="{ number: 678 }">678</option>
</select>
<span>selected_option的值为{{selected_option}}</span>
表单修饰符
在默认情况下, v-model 在 input 事件中同步输入框的值与数据
要想在change事件下更新数据则使用v-model.lazy 如
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >
组件
组件(Component)可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。
注册一个全局组件,你可以使用 Vue.component(tagName, options)。(设置一个全局自定义组件的话,是用Vue创建出所有的实例对象都可以用这个组件来玩) 例如:
Vue.component('my-component', {
// 选项
})
注意:要确保在初始化根实例 之前 注册了组件
想让某个实例使用其特有的组件,则使用局部组件
如:
<!-- 仅在父模板id为app下可用 -->
<div id="app">
<my-component><my-component>
<!-- 父模板会将上面渲染为<div>A custom component!</div>-->
</div>
<script type="text/javascript">
var Child = { template: '<div>A custom component!</div>'}
var vm=new Vue({
el: '#app',
components: { //<my-component>将只在父模板可用
'my-component': Child
}
})
</script>
DOM 模版解析说明
Vue 只有在浏览器解析和标准化 HTML 后才能获取模版内容。尤其像这些元素 <ul> , <ol>, <table> , <select> 限制了能被它包裹的元素,<option> 只能出现在其它元素内部。
当使用自定义组件和这些受限制的元素会导致一些问题:下面是运行不成功的
<table id="app">
<my-row></my-row>
</table>
<script type="text/javascript">
var Child = { template: '<div>A custom component!</div>'}
var vm=new Vue({
el: '#app',
components: {
'my-row': Child
}
})
</script>
变通的方案是使用特殊的 is 属性:
<table id="app">
<tr is="my-row"></tr>
</table>
<script type="text/javascript">
var Child = { template: '<div>A custom component!</div>'}
var vm=new Vue({
el: '#app',
components: {
'my-row': Child
}
})
</script>
应当注意,如果您使用来自以下来源之一的字符串模板,这些限制将不适用:
①<script type="text/x-template">
②JavaScript内联模版字符串
③.vue 组件
因此,有必要的话请使用字符串模版。-->/*指的是template中使用字符串规定的字符串标签*/
使用组件时,data属性 必须是函数。否则会提示”[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.”
构成组件
通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B 。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
在 Vue.js 中,父子组件的关系可以总结为 props down, events up 。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。
组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。可以使用 props 把数据传给子组件。
prop 是父组件用来传递数据的一个自定义属性。子组件需要显式地用 props 选项 声明 “prop” /*子组件接收父组件的数据用props属性*/
prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。