精读 Vue 官方文档系列 ?
访问元素 & 组件
$root
访问根组件实例
$parent
获取父组件实例,支持多次调用,获取连续多层父级的实例。
ref & $refs
获取子组件的实例
<children ref="child" />
获取 DOM 元素的对象引用。
<input type="text" ref="input" />
最终,我们可以在组件的 $refs
属性中访问这些 ref
的对应的引用。
mountd(){
this.$refs.child.input.foucs();
}
依赖注入
使用 provide
提供依赖,再使用 inject
注入依赖。
Provider
provide: function(){
return {
getMapData: this.getData
}
}
Consumer
inject:['getMapData']
这对组件选项必须要一起使用。以允许一个祖先组件向其所有后代组件注入一个依赖,不论组件的层级有多深。
provide
的值是一个对象或者是返回一个对象的函数。对象的 key 便是向子孙组件中注入的依赖。
inject
的值是一个字符串数组,或者是一个对象选项。这些数组元素或者是对象的 key 都是对应的都是 provide
注入的依赖。
最基本的形式:
Vue.extend({
name: "Parent",
provide: {
foo: "bar",
},
});
Vue.extend({
name: "Son",
inject: ["foo"],
created() {
console.log(this.foo);
},
});
当 provide
的值为一个函数,inject
的值是一个对象选项:
Vue.extend({
name: "Parent",
provide() {
return {
foo: "bar",
};
},
});
Vue.extend({
name: "Son",
inject: {
bar: {
from: "foo",
default: "new bar",
},
},
});
如果 inject
的值是一个对象,那么from
便可以指定来源,default
用来设置依赖的默认值。但是当你的依赖默认值不是一个基本类型时,必须要使用一个工厂方法来返回这个值。
{
inject: {
foo: {
from: 'bar',
default: () => [1, 2, 3]
}
}
}
最后,因为 provide/inject
的初始化优先于 props
,data
,所以我们便可以用依赖注入来初始化它们的默认值。
Vue.extend({
inject: ["foo"],
props: {
bar: {
type: String,
default: () => this.foo,
},
},
data() {
return {
copy_bar: this.foo,
};
},
});
依赖注入解决了什么问题?
- 解决了
$parent
无法很好的扩展到更深层级的嵌套组件上。 - 给任意的后代提供数据或方法,免去了多层的 Prop 传递。
- 任意的后代也不需要关心 property 是从何处注入。
依赖注入的应用场景:
- 编写一个固定组件集,存在一个根组件和多层的子组件,且结构固定。
- 一个局部的数据中心化。
依赖注入的负面影响:
- 注入的数据或方法基于设计的考量不具有响应式的特性。
- 注入的数据虽然不会被处理为响应式数据,但是并不阻止依赖注入一个本是响应式的数据。
- 会将应用程序中相关的组件(使用依赖注入的组件)紧密的耦合在一起,使得重构变得比较困难(这是依赖注入的本质所决定的)。
程序化的事件监听器
程序化的事件监听器是建立在 Vue 系统上的,它区别于浏览器的事件系统(EventTarget API)。
通常我们使用 v-on
在组件上监听事件,使用 $emit()
在组件内触发事件,而 “程序化的事件监听器” 提供了一个可以在组件实例上监听事件的功能。
$on('eventName', eventHandler)
绑定/侦听一个事件。$off('eventName, eventHandler')
解绑/停止侦听一个事件。$once(eventName, eventHandler)
一次性绑定/监听一个事件。
善用 $once
可以提高我们解决组件事件清理的麻烦。
Bad
// 一次性将这个日期选择器附加到一个输入框上
// 它会被挂载到 DOM 上。
mounted: function () {
// Pikaday 是一个第三方日期选择器的库
this.picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
},
// 在组件被销毁之前,
// 也销毁这个日期选择器。
beforeDestroy: function () {
this.picker.destroy()
}
Good
mounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
递归组件
所谓“递归”就是自己调自己,同理组件递归就是组件不断的调用自身。
递归组件的入口:
<x-menu :menus="menus"></x-menu>
递归组件的定义:
Vue.component('x-menu', {
props:{
menus:{
requried:true,
type:Array
}
},
template:`
<ul>
<li v-for="menu in menus" :key="menu.key">
<div>{{ menu.name }}</div>
<!--核心所在-->
<x-menus v-if="menu.children"></x-menus>
</li>
</ul>
`
});
循环引用
与递归组件不同的是,递归是通过不断调用自己来实现所需的功能。而循环引用只会存在两个组件之间,A 组件使用了 B 组件,B 组件也使用了 A 组件。
通常这种问题只会出现在使用模块化系统来引入具有相互引用关系的组件。
解决的办法有两种:
1. 手动注册其中的一个组件
beforeCreate: function(){
this.$options.components.ComponetB = import('./components/componentB').default;
}
2. 使用异步组件
{
components:{
'component-b': ()=>import('./components/componentB')
}
}
模板定义的替代品
我们更多的推荐使用单文件组件 SFC 的方式定义模板或者在 template
属性中编写字符串模板,并不建议将组件的模板与逻辑相分离。
内联模板
当 inline-template
这个特殊的 attribute 出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容(不在是理解中 slot 的性质)。这使得模板的撰写工作更加灵活。
内联模板需要定义在 Vue 所属的 DOM 元素内。
<my-component inline-template>
<div>
<p>These are compiled as the component's own template.</p>
<p>Not parent's transclusion content.</p>
</div>
</my-component>
X-Template
与内联模板相比就是使用具有特殊 type
值与 id
属性的 <script>
标签来存储模板内容。
x-template 需要定义在 Vue 所属的 DOM 元素外。
<script type="text/x-template" id="hello-world-template">
<p>Hello hello hello</p>
</script>
id
的作用就是将模板内容与模板逻辑进行连接的凭据。
Vue.component('hello-world', {
template: '#hello-world-template'
})
强制更新
调用 this.$forceUpdate()
可以强制更新组件。
通过 v-once
创建低开销的静态组件
当组件包含了大量静态内容时。我们可以在根元素上添加 v-once
attribute 以确保这些内容只计算一次然后缓存起来,提供组件的渲染速度。
Vue.component('terms-of-service', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!