组件注册
.component()接收2个参数,其中第一个参数是组件名(数据类型是字符串)
组件名命名:
全部小写,多个单词用连字符连接(-减号)
因为html中是大小写不敏感的,浏览器会将大写解析为小写,因此不要使用驼峰命名法来命名自定义标签,而是使用连字符分隔
组件被引用时,也必须是相同的名,例如:组件名是img-data,那么被引用时标签为,闭不闭合看组件的定义,如果组件的定义是img之类的,就不需要闭合
直接暴露在vue实例的组件都是全局组件,可以直接在组件实例中调用
局部组件是使用一个JavaScript对象进行定义封装,例如:
<div id="app">
<datas-a></datas-a>
</div>
<script>
const datas ={
template: `
<div>
hallo
</div>
`
}
const hallo = Vue.createApp({
components: {
"datas-a" : datas
}
}).mount('#app')
</script>
components对象,键为自定义元素的名称,值为组件的实质对象
局部组件的属性是不能直接被调用的,但是可以在另一个组件中指向其为自己的子组件,例如:
const datab ={
components: {
"datas-a" : dataa
}
}
模块系统
通过导入模块的方式导入组件,例如:
import datas from ‘./datas’
那么datas组件就是可以在当前使用了
Props
prop类型
用对象的方式列出prop,并且定义其类型,当传入的prop类型不对就会报错(开发版本),例如:
const hallo = Vue.createApp({
component: {
props:{
abc: String,
xyz: Boolean,
},
template: `<h1>{{abc.text}}-{{xyz.text}}<h1>`
}
}).mount('#app')
如果没有限制类型,那么任何类型的值(能装进变量里的值都行,因为连变量里面的值都可以传入)都可以传给prop
传入数字
传入布尔值
传入数组
传入对象
单向数据流
父组件的prop数据可以流向子组件,但是子组件不能流向父组件,避免因为子组件而修改了父组件
父组件发生变化时,子组件的prop都会刷新为当前最新的值
属性继承
可以在组件中写属性,例如:
template: \`<div class="main"></div>\`
同样也是可以在组件写事件监听器之类的
禁用属性继承
inheritAttrs: false,
template: \`<div class="main"></div>\`
包含未被props接收的参数
this.$attrs
可以根据需求来传入属性,例如:
<test class="data"></test>
<div :class="$attrs.class"></div>
父子组件之间通过事件进行通信
vue实质上是单向数据流,子组件不能修改父组件传递的数据,不过可以通过事件来进行修改,props传递数据:只能父传子,而不能子传父
因此vue提供了自定义事件来先父组件传递数据,然后父组件监听子组件的事件
自定义事件
如果定义了原生事件,那么组件的事件将会代替原生事件
emits选项可以定义事件
兄弟(非父子)组件数据交互
通过一个事件中心(实质上这是一个发布-订阅模型)来管理组件间的通信
这个事件中心叫Vue事件总线(EventBus)
let hallo = new Vue()
监听事件和销毁事件
hallo.$on(“onadd”, onAdd)
hallo.$off(“onadd”)
触发事件
hallo.$emit(“onadd”, id)
组件插槽
const app = Vue.createApp({
template: `
<div>
<hallo>
<test/>
</hallo>
</div>
`
})
app.component('test', {
template: `<span>hahaha</span>`
})
app.component('hallo', {
// props: ['num'],
template: `
<div>hallo word
<slot></slot>
</div>
`
})
const vm = app.mount("#app")
内部的内容就是vuejs,插槽可以表示任何的DOM元素,子组件一样也可以表示
当插槽使用了动态数据时,以根组件的data属性为准
插槽默认值
app.component('test',{
template:`
<div>
data:<slot><span>hallo word</span></slot>
</div>
`
})
当插槽没有dom元素需要表示,将显示hallo word,当有dom元素表示时,会替换该元素
具名插槽:可以给slot和子组件分别使用name属性,slot属性,当name属性和slot属性相同,那么就匹配
当出现多个插槽时,希望一个插槽代表一个dom元素时,就可以具名插槽了,例如:
const app = Vue.createApp({
template: `
<test>
<template v-slot:a><div>我是第一个</div></template>
<template v-slot:b><div>我是第三个</div></template>
</test>
`
})
app.component('test',{
template:`
<div>
<slot name="a"></slot>
<div>hallo word</div>
<slot name="b"></slot>
</div>
`
})
const vm = app.mount("#app")
另外v-slot可以简写成#a
作用域插槽可以访问子组件定义的数据,例如:
const app = Vue.createApp({
template: `
<test v-slot="props">
{{props.item}}
</test>
`
})
app.component('test', {
data() {
return {
items: ['hallo', 'hahaha','abc','hallo word','xyz']
}
},
template: `
<ul>
<li v-for="(item, index) in items">
<slot :item="item"></slot>
</li>
</ul>
`
})
其中props是子组件传递过来的数据(对象格式)
简化作用域插槽写法
const app = Vue.createApp({
template: `
<test v-slot={item}>
{{item}}
</test>
`
})
动态组件
const app = Vue.createApp({
data(){
return {
hallo:'test'
}
},
template: `
<keep-alive>
<component :is="hallo"></component>
</keep-alive>
`
})
app.component('test', {
template: `
<div>hallo word</div>
<input />
`
})
决定渲染组件由hallo决定,在上面例子中可以看到hallo指向了test,因此渲染的是test,不需要手动设置子组件,而是动态设置,只需要修改:is指向的值就可以了
而且当使用动态组件时,切换该组件后,该组件的状态将会失活,无法保存状态,需要搭配使用,保存这些状态,不只是方便保存缓存,而且还可以避免重新渲染
异步组件
const app = Vue.createApp({
data(){
return {
hallo:'asyncs'
}
},
template: `
<keep-alive>
<component :is="hallo"></component>
</keep-alive>
`
})
app.component('asyncs', Vue.defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
template: `<div>hallo word</div>`
})
},1000)
})
}))
const vm = app.mount("#app")
可以看到该组件并不会立马渲染,该组件不会在第一次加载渲染时显示,而是当需要用到它时才会渲染,可以优化页面首次渲染性能
provide/inject
当存在多级组件时,祖先组件想传递组件给子孙组件时,如果使用props传递数据的话,需要一层接收然后在传递给后辈,非常麻烦
const app = Vue.createApp({
data(){
return {num: 100}
},
provide:{
haha: 200
},
template: `
<hallo :num="num" />
`
})
app.component('hallo',{
props:['num'],
inject:['haha'],
template:`
<div>{{num}},{{haha}}</div>
`
})
这里只是举个例子,如果是多层组件结构,这个方法也是可以发送和接收到的,只需要provide发送一下数据,然后子组件inject接收一下
–
Vue.extend(),vue基础构造器,会创建一个子类,参数是包含组件的对象,例如:
<div id='app'>
</div>
<script>
const Test = Vue.extend({
template: '<p>{{a}} {{b}} {{c}}</p>',
data: function () {
return {
a: 'hallo',
b: 'abc',
c: 'xyz'
}
}
})
new Test().$mount('#app')
<script>
受控组件和非受控组件