这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战
组件化
组件的定义:实现应用中局部代码和资源的集合。
使用组件的注意事项:
- 组件名:组件命名需要使用kebal-case方式,不能使用CamelCase命名。但是在脚手架中两者都可以使用。
- 组件标签:必须使用双标签,不能使用单标签,使用单标签后,后面的组件不能渲染。但是在脚手架中两者都支持。
- const shool = Vue.extend(options) 可简写为:const school = options
- 没有el配置选项。
关于VueComponent
const school = Vue.extend({
name: "schools",
template: `<p>{{name}}</p>`,
data() {
return {
name: "liuzhuang",
age: this.getdate(),
};
},
methods: {
getdate() {
console.log(this);
},
},
});
-
当我们使用Vue.extend()创建组件时,实质上返回的是一个VueComponent构造函数。
-
当我们使用标签使用组件时,Vue会帮解析创建实例对象,即执行 new VueComponent(options);
-
当我们创建组件,每次调用Vue.extend时,返回的都是一个全新的VueCompont构造函数。
-
this指向:
(1)在组件配置中:data函数,methods中的函数,watch中的函数,computed中的函数,它们的this都是指向【VueComponent实例对象】。
(2)在Vue实例对象配置中:data函数,methods中的函数,watch中的函数,computed中的函数,它们的this都是指向【Vue实例对象】。
内置关系
Vuecomponent.prototype.--prop-- =Vue.prototype
组件化的三个步骤:
1、创建组件构造器
Vue.extend({ template: 模板 })
2、注册组件
Vue.component({ 标签名,构造器名字})
3、使用组件
全局组件:
在页面任何地方都可以使用
const cpnC = Vue.extend({
template: `
<div>
<h1>你好啊</h1>
<p>第一个vue组件化实例</p>
</div>`
})
注册组件
Vue.component('my-cpn', cpnC);
局部组件:
只能在
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<script>
//创建组件构造器对象
const cpnC = Vue.extend({
template: `
<div>
<h1>你好啊</h1>
<p>第一个vue组件化实例</p>
</div>`
})
const app = new Vue({
el: '#app',
data: {
message: 546
},
//局部注册
components: {
//标签名:组件构造器
cpn: cpnC
}
})
</script>
父子组件
原理:通过父组件来注册和使用子组件。
<div id="app">
<cpn2></cpn2>
</div>
<script src="./vue.js"></script>
<script>
//组件构造器1
const cpnC1 = Vue.extend({ //子组件
template: `
<div>
<p>我是one</p>
</div>
`,
})
//组件构造器1
const cpnC2 = Vue.extend({ //父组件
//使用cpn1组件
template: `
<div>
<p>我是two</p>
<cpn1></cpn1>
</div>
`,
components: { //用cpn2来注册cpn1
//此时cpn2是cpn1的父组件
cpn1: cpnC1
}
})
//根组件
const app = new Vue({
el: '#app',
data: {
message: 'one'
},
components: {
cpn2: cpnC2
}
})
</script>
创建组件语法糖
全局组件语法糖:
Vue.component('cpn1', {
template: `
<div>
<p>我是one</p>
</div>
`,
})
局部组件语法糖:
components: {
'cpn1': {
template: `
<div>
<p>我是one</p>
</div>
`
}
}
template模板的分离写法
<!-- 分离写法2 -->
<template id="cpn">
<div>
<p>我是tow</p>
</div>
</template>
组件中的data属性
data属性必须是一个函数,目的是为了让每一个组件都有自己的对象,防止连锁反应。如果data对象时,那么每一个组件都指向同一个data对象,一个组件改变data中的值,其他的复用组件也会改变,这就是连锁反应。
例如:
//根组件模板
<div id="app">
<cpn1></cpn1>
<cpn1></cpn1>
</div>
//cpn子组件模板
<script type="text/x-template" id="cpn">
<div>
<p>{{one}}</p>
<button @click=one-->-</button>
<button @click=one++>+</button>
</div>
</script>
const app = new Vue({
el: '#app',
data: {
message: 'one'
},
components: {
'cpn1': {
template: '#cpn',
data() {
return {
one: 0,
};
},
},
}
})
多次使用组件时,改变one的值,不会影响另一个的组件的值。
父子组件向子组件传递数据(props)
详见我的这篇文章 juejin.cn/post/705340…
子组件向父组件发射事件
详见我的这篇文章 juejin.cn/post/705443…
全局事件总线
当两个组件不是父子关系时,我们可以通过全局事件总线来进行通信。
定义全局事件总线:
new Vue({
render: (h) => h(App),
beforeCreate() {
Vue.prototype.$bus = this;
},
}).$mount("#app");
使用:和自定义事件的使用方式一样,
//绑定事件
this.$bus.$on("getname", (name) => {
console.log(name);
});
//发射事件
this.$bus.$emit('getname',this.name);
//解绑事件
this.$bus.$off('getname');
插槽
插槽的使用可以使我们的组件更加灵活,可以有使用组件的人控制在组件中插入哪些元素,提高了组件的复用性和灵活程度。
默认插槽的使用
注意点:
- 在使用组件时,我们在组件中插入的标签,都会插入到一个插槽当中。在子组件中多次使用插槽,插入的标签会多次渲染。
- 我们可以在插槽中编写后备内容,就是当我们在使用组件时,如果没有插入标签,则会渲染插槽中后备的内容。
//父组件中使用cpn组件
<div id="app">
<cpn>
<h3>465</h3>
<h4>你好</h4>
</cpn>
</div>
//子组件
<template id="cpn">
<div>
<slot><span>hello</span></slot>
</div>
</template>
具名插槽
为slot添加name属性,然后在插入标签的时候,我们需要使用<template>包裹我插入的内容,并且使用v-slot属性知名要插入到那个插槽当中。
v-slot:可以简写为#
//父组件
<div id="app">
<cpn>
<template v-slot:header>
<button>按钮</button>
</template>
</cpn>
<cpn>
//使用简写#
<template #:center>
<button>按钮</button>
</template>
</cpn>
</div>
//子组件
<template id="cpn">
<div>
<slot name="left"><span >左</span></slot>
<slot name='center'><span >中</span></slot>
</div>
</template>
作用域插槽
在某个场景下,我们需要父组件来控制插入的标签的样式,或者修改显示的内容时,当时数据实在子组件中的,这个场景下我们可以使用作用域插槽。
我使用插槽时,接受到的值是一个对象,因此,我们可以对它进行结构。重命名,赋默认值等操作。
//赋默认值
{ SlotName = 'wangwu' }
//重命名,将SlotName改为sName
{ SlotName : sName }
//子组件name值
name:zhangsan
//子组件
<template>
<div class="son">
<h1>{{ title }}</h1>
//绑定prop数据SlotName,发送给使用该组件的父组件
//作用域插槽和具名插槽结合
<slot name="content" :SlotName="name"></slot>
<h4>间隔</h4>
//默认插槽和作用域插槽结合,传输一个普通的字符串
<slot SlotName="年后"></slot>
</div>
</template>
//父组件
<son title="美食">
//作用域插槽和具名插槽结合
<template #content="{ SlotName }">
<a href="">百度</a>
<span>{{ SlotName }}</span>
</template>
//默认插槽和作用域插槽结合
<template #default="{ SlotName }">
<a href="">淘宝</a>
<span>{{ SlotName }}</span>
</template>
</son>