温故而知新之VUE(三)
组件
// 全局注册
Vue.component('button-counter', {
// data 选项必须是一个函数,这样每个实例才可以维护一份被返回的data对象的独立拷贝
data: function(){
return {
count: 0
}
},
template: '<button @click="count++"> {{ count }}</button>'
})
// 使用时
<button-counter />
通过Props向子组件传递数据
Vue.component('blog-post', {
props: ['post'],
template: `
<div class="blog-post">
<p>{{ post.title }}</p>
</div>
`
})
通过事件向父级组件发送消息
通过 this.$emit(fnName, data)发送数据
组件上 on 绑定 fnName接收数据
在组件上使用v-model
<input v-model="searchText" />
//等价于
<input :value="searchText" @input="searchText=$event.target.value" />
当用在组件上
<custom-input :value="searchText" @input="searchText=$event" />
Vue.component('custom-input', {
props: ['value'],
template: `
<input :value="value" @input="$emit('input', $event.target.value)">
`
})
// 现在可以使用v-model
<custom-input v-model="searchText" />
通过插槽分发内容(slot)
动态组件
// 组件会在currentComponent改变时改变
<component v-bind:is = "currentComponent" ></component>
解析DOM模板时的注意事项
<table>
<tr is="blog-pist-row"></tr>
</table>
如果我们从以下来源使用模板时,这条限制是不存在的
- 字符串(例如: template:"")
- 单文件组件(.vue)
深入了解组件
组件注册
Vue.component(name, {
})
#组件名大小写
- 使用kebab-case(短横线)
- 使用PascalCase(驼峰式命名)
局部注册
var ComponentA = { }
new Vue({
el: "#app",
components: {
ComponentA
}
})
Props
#大小写
在HTML中使用短横线
<blog-post post-title="hello"></blog-post>
#Prop类型
props: {
title: String
}
// 即使数据是静态的,也需要用v-bind来绑定,告诉vue这是一个js表达式,而不是一个字符串
<blog-post :comment-ids="[234,54,3]" />
#单向数据流
父组件通过props传递数据给子组件,自上向下流动
#Prop验证
props: {
propA: [String,Number],
propB: Number,
propC: {
type: String,
default: "iing"
},
propD: {
// 自定义验证函数
validator: function(value){
return ['success','warning'].indexOf(value) !==-1
}
}
}
#非Prop的特性
#替换/合并已有的特性
#禁用特性继承
设置inheritAttrs: false
Vue.component('my-componnet', {
inheritAttrs: false
})
自定义事件
事件名推荐使用短横线命名
v-on:myEvent 会渲染成 v-on:myevent,所以导致myEvent不能被监听到
#自定义组件的v-model
2.2.0+新增
Vue.component('base-checkbox', {
model: {
prop:"checked",
event: "change"
},
props: {
checked: Boolean
},
template: `
<input type="checkbox" :checked="checked" @change="$emit('change', $event.target.checked)" />
})
<base-checkbox v-model="msg" />
#将原生事件绑定到组件
// .native修饰符
<base-checkbox v-on:focus.native="onFocus" />
提供了一个$listeners属性,它是一个对象,里面包含了作用在这个组件上的所有监听器,
#.sync修饰符
2.3.0+新增
插槽slot
#具名slot
<slot name="header"></slot>
// 插入的内容
<div slot="header">...</div>
#插槽的默认内容
<slot>default content</slot>
#编译作用域
父组件模板的所有东西都会在父级组件作用域内编译,子组件模板的所有东西都会在子级作用域内编译
#作用域插槽
2.1.0+新增
动态组件&异步组件
#在动态组件上使用keep-alive VS 使用is
使用is:每次都会创建一个新的组件
使用keep-alive:会缓存
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
#异步组件
实现按需加载
// 结合webpack中的code-splitting功能一起使用
Vue.component('async-webpack-example', function(resolve){
//这个require语法会告诉webpack自动将你的构建代码切割成多个包,这些包会通过Ajax请求加载
require(['./my-async-component'], resolve)
})
或可以
// 使用webpack2和ES6语法结合
new Vue({
components: {
'my-component': ()=>import('./my-async-component')
}
})
#处理加载状态
2.3.0+新增
const AsyncComponent = ()=> ({
// 需要加载的组件
component: import('./MyComponent.vue'),
//异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间,默认值为200毫秒
delay: 200,
// 超时时间
timeout: 3000
})
// 如果在vue-router上使用,需要vue-router在2.4.0+版本
处理边界情况
访问元素&组件
#访问根实例
this.$root // 根实例
this.$parent // 父级组件
<base-input ref="usernameInput" />
// this.$refs.usernameInput 调用
refs
#依赖注入
两个新的实例选项provide 和 inject
provide: 允许我们指定想要提供给后代组件的数据和方法
provide: function(){
return {
getMap: this.getMap
}
}
// 在任何后代组件中,都可以使用inject 选项来接收指定的我们想要添加在实例上的属性/方法
inject: ['getMap']
依赖注入相对于$parent有优势,但缺点是造成组件之间的耦合度提高,中大型项目建议VUEX
程序化的事件监听器
方法:
once(eventName, eventHandler) 一次性侦听一个事件
$off(eventName, eventHandler) 停止侦听一个事件
mounted: function(){
this.picker = new Pikaday({
field: this.$refs.input
})
// 监听 组件销毁前 销毁这个实例
this.$once('hook:beforeDestroy', function(){
picker.destroy()
})
}
循环引用
#递归组件
通过name选项来调用自身
注意跳出递归的条件,避免无限循环
name : 'stack-overflow',
template: '<div><stack-overflow /></div>'
#组件之间的循环引用
#内联模板
inline-template
控制更新
#强制更新
通过$forceUpdate
通过v-once创建低开销的静态组件,当需要渲染大量静态内容时,不然没必要使用,也不应该过度使用