基础知识
Vue.js设计理念与MVVM模式
Vue.js以数据驱动和组件化的思想构建, 时一个目前非常火的JavaScript MVVM库. Vue.js以数据驱动, 并通过特殊的HTML语法将DOM与数据绑定, 实现DOM与数据保持同步.
在上图中,ViewModel是Vue.js的核心, DOM Listeners与Data Bindings两个工具实现了数据的双向绑定,DOM Listeners 监测页面上的DOM元素变化, Data Bindings实现了在Vue实例变化时, 更新页面中的DOM元素.
Vue.js常用指令
指令定义: Vue.js的指令都以v-开头, 作用与html元素, 当指令绑定在元素上时,指令会为该元素添加一些特殊的行为, 可以把指令堪称是特殊的html特性.
v-model指令: 数据双向绑定
v-if/v-else指令: 条件渲染
v-for指令: 遍历渲染, 用于渲染列表
v-show指令: 渲染指令, 相当于CSS中的style属性
v-bind指令: 用法: v-bind: 属性 = “”,简写: :属性 =”” , 用于给该html元素某个属性渲染
v-on指令: 用法: v-on: 事件 = “”, 简写: @事件 = “”,用于监听DOM事件, 使用方式有两种, 一是绑定一个方法(事件指向方法的引用), 二是直接使用内联语句.
Vue.js的组件
组件介绍
定义: 组件是自定义的html元素, 组件中封装了可复用的html代码, 组件扩展了html元素.
作用: 通过一个个相互独立的小组件的复用可以构建大型的应用.
使用步骤: 1.创建组件构造器(Vue.extend()方法, 该方法是Vue构造器的扩展, 创建的是组件构造器) , 2.注册组件(Vue.component()方法, 方法有两个参数,第一个是组件的标签, 第二个是组件的构造器), 3.在Vue实例的作用域内使用组件(组件必须挂载到摸个Vue实例下).
理解: 组件是把封装好的可复用的html代码块自定义为自己的html标签, 挂载到某个Vue实例上使用时, 与普通的html标签使用方法相同.
全局注册与局部注册
全局注册: Vue.component(), 表示该组件可以在任意的Vue实例下使用.
局部注册: 使用选项对象的components属性实现, 则注册的组件只能在该选项对象中使用.
注册组件的语法糖
全局注册
// 全局注册,my-component1是标签名称
Vue.component('my-component1',{
template: '<div>This is the first component!</div>'
})
var vm1 = new Vue({
el: '#app1'
})
局部注册
var vm2 = new Vue({
el: '#app2',
components: {
// 局部注册,my-component2是标签名称
'my-component2': {
template: '<div>This is the second component!</div>'
},
// 局部注册,my-component3是标签名称
'my-component3': {
template: '<div>This is the third component!</div>'
}
}
})
template标签
…实现了html代码与JavaScript代码分离, 通过id就可以查找对应元素, 更方便代码阅读与维护.
父组件与子组件
定义: 在组件中定义和使用其他组件, 即构成了父子组件关系.
在上图中, Child组件在Parent组件中注册, 所以只能在Parent组件中使用, 更准确的说: 子组件只能在父组件的template中使用.
两个注意点:
1. 子组件组件不能以子标签的形式在父组件中使用, 因为子组件注册到父组件时, Vue.js已经编译好父组件的模板, 模板的内容已经决定了父组件要渲染的html, 在运行时…中的子标签只会被当做普通的html代码执行, 二不是标准的html标签, 会被浏览器直接忽略掉.
2. 不能在父组件外使用子组件.
组件中的props
组件作用域: 在Vue.js中, 组件的作用域是孤立的, 所以不可以在子组件中直接引用父组件的数据.
作用: 子组件通过props属性, 来接收父组件传来的数据.
例:
<template id="childComponent">
<table>
<tr>
<th>
子组件数据
</th>
</tr>
<tr>
<td>child name</td>
<td>{{ childName }}</td>
</tr>
<tr>
<td>child age</td>
<td>{{ childAge }}</td>
</tr>
</table>
</template>
<div id="app">
<child-component v-bind:child-name="name" v-bind:child-age="age"></my-component>
</div>
var vm = new Vue({
el: '#app',
data: {
name: 'aaa',
age: 28
},
components: {
'child-component': {
template: '#childComponent',
props: ['childName', 'childAge']
}
}
})
注意: 在以上例子中, 子组件中定义props时使用camelCase命名法, 而html特性不区分大小写, 所以在html代码块中要转换为kebab-case. 即在props中定义的childName, 在html代码中作为特性属性时转换为child-name.
在父组件中使用子组件时, 使用如下语法将传递数据给子组件.
<child-component v-bind: 子组件prop = "父组件数据属性">
</child-component>
props绑定类型:
1. 单项绑定: 数据单向从父组件传递给子组件, 修改子组件的数据, 父组件的数据不会受影响.
2. 双向绑定: .sync用于显式指定双向绑定, 此时修改子组件数据会同时修改父组件数据
<child-component v-bind: 子组件prop.sync = "父组件数据属性">
</child-component>
3.单次绑定: .once用于显式指定单次绑定, 单次绑定在父组件首次传递数据给子组件后, 再不会同步数据变化.
<child-component v-bind: 子组件prop.once = "父组件数据属性">
</child-component>
组件的内容分发
定义: 使用内容分发实现组件的组合, 即实现混合父组件自己的内容与自己件模板件的混合.
使用:
<!--子组件中-->
<slot name="header"></slot>
<!--父组件中-->
<p slot="header">...</p>
父子组件间的访问
父组件访问子组件实例: 使用children或refs, 在父组件中通过this.children访问的时所有子组件,得到的是一个数组;通过this.refs.索引Id 访问的是指定的子组件, 在子组件中通过v-ref:索引Id 来指定自己的索引Id.
子组件访问父组件实例: 使用parent子组件访问跟组件实例:使用root
注: 要尽量避免子组件直接依赖父组件的数据, 而是通过props做数据显式数据传递, 这样既减少父子组件间的耦合,同时也避免了父组件被任意子组件修改而使父组件状态难以理解.
父子组件的自定义事件
目的: 实现父子组件各自有事件触发时可以相互通知.
实现: Vue实例实现了自定义的事件接口, 用于在组件树中通信, 这个事件系统独立于原生的DOM事件.每个Vue实例都可以理解为一个事件触发器:
- 使用$on()监听事件
- 使用$emit()触发事件
- 使用$dispatch()派发事件,实现事件沿父链冒泡
- 使用$broadcast()广播事件,实现事件向下传导给所有的后代.
派发事件举例:
<div id="app">
<p>Messages: {{ messages | json }}</p>
<child-component></child-component>
</div>
<template id="child-component">
<input v-model="msg" />
<button v-on:click="notify">Dispatch Event</button>
</template>
<script src="js/vue.js"></script>
<script>
// 注册子组件
Vue.component('child-component', {
template: '#child-component',
data: function() {
return {
msg: ''
}
},
methods: {
notify: function() {
if (this.msg.trim()) {
this.$dispatch('child-msg', this.msg)
this.msg = ''
}
}
}
})
// 初始化父组件
new Vue({
el: '#app',
data: {
messages: []
},
events: {
'child-msg': function(msg) {
this.messages.push(msg)
}
}
})
</script>
我们将这个示例分为几个步骤解读:
子组件的button元素绑定了click事件,该事件指向notify方法
子组件的notify方法在处理时,调用了$dispatch,将事件派发到父组件的child-msg事件,并给该该事件提供了一个msg参数
父组件的events选项中定义了child-msg事件,父组件接收到子组件的派发后,调用child-msg事件。
广播事件举例
<div id="app">
<input v-model="msg" />
<button v-on:click="notify">Broadcast Event</button>
<child-component></child-component>
</div>
<template id="child-component">
<ul>
<li v-for="item in messages">
父组件录入了信息:{{ item }}
</li>
</ul>
</template>
<script src="js/vue.js"></script>
<script>
// 注册子组件
Vue.component('child-component', {
template: '#child-component',
data: function() {
return {
messages: []
}
},
events: {
'parent-msg': function(msg) {
this.messages.push(msg)
}
}
})
// 初始化父组件
new Vue({
el: '#app',
data: {
msg: ''
},
methods: {
notify: function() {
if (this.msg.trim()) {
this.$broadcast('parent-msg', this.msg)
}
}
}
})
</script>
我们将这个示例分为几个步骤解读:
父组件的button元素绑定了click事件,该事件指向notify方法
父组件的notify方法在处理时,调用了$broadcast,将事件派发到子组件的parent-msg事件,并给该该事件提供了一个msg参数
子组件的events选项中定义了parent-msg事件,子组件接收到父组件的广播后,调用parent-msg事件。