vue组件
vue 的组件
-
组件是可复用的 Vue 实例,且带有一个名字:
-
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
-
组件模板必须只能存在一个根元素
组件的注册
全局注册
Vue.component('自定义的组件名', 组件的配置项)
// 组件的配置项 : template, data, methods, computed , filter .... 等属性
Vue.component('自定义的组件名', {
template:``
})
组件名
- 连字符:都使用小写字母形式: 因为 html对大小写不敏感,会自动转换为小写形式
- 驼峰命名:当使用时,如果在HTML中转换为连字符形式, 如果在模板字符串中或者单文件组件中则不受限制
组件中的data属性
组件中的data必须是一个函数; 每个实例可以维护一份被返回对象的独立的拷贝;实例的data属性就都是独立的,不会相互影响 ;也是为了和 vue 实例中的data 进行区分
局部注册
在组件内部使用 components 属性进行局部注册; 以后推荐使用局部注册
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
组件的传值方式
- 父子传值(通信)
- 子父传值(通信)
- 非父子传值(通信)
组件的关系
- 父子关系
- 非父子关系
组件父子通信
通过 prop属性实现
- 传递一个静态的数据:
在组件标签上自定义一个属性,并赋值
<组件标签名 自定义属性='value'></组件标签名>
在子组件的内部,通过 props 选项进行接受 props:['自定义属性名']
; 接受后可以在组件内部使用, 使用的方式和data中的数据一样
Vue.component('自定义的组件名', {
template:`<div>接受后可以在组件内部使用, 使用的方式和data中的数据一样</div>`
props:['组件标签上自定义属性名']
})
- 传递一个动态的数据: 父子通信
需要在组件标签上绑定自定义属性,自定属性的值是父组件中的data中的key数据
<组件标签名 v-bind:自定义属性='父组件中data中的key'></组件标签名>
在子组件的内部,通过 props 选项进行接受 props:['自定义属性名']
; 接受后可以在组件内部使用, 使用的方式和data中的数据一样
Vue.component('自定义的组件名', {
template:`<div>接受后可以在组件内部使用, 使用的方式和data中的数据一样</div>`
props:['组件标签上自定义属性名']
})
组件子父通信
$on() 和 $emit()
子父通信需要通过事件进行传递, 通过 e m i t ( ) 和 emit() 和 emit()和on() 实现; $emit()触发一个自定义事件, o n ( ) 监 听 自 定 义 事 件 ∗ ∗ on()监听自定义事件 ** on()监听自定义事件∗∗on() 和 $emit() 必须属于同一个对象,才能进行监听; $on()通常在created中进行监听**
$emit()用法
// 单纯触发一个自定义事件
vm.$emit('自定义事件名')
// 可以接受第二个参数, 传递数据
vm.$emit('自定义事件名', data)
$on()用法
vm.$on('监听自定义事件', (data) => {
// 回调函数的参数data就是传递的数据
})
子父通信
- 触发事件:在子组件内部定义一个原生事件,通过该原生事件触发一个自定义事件
// 在方法中通过this.$emit() 触发
Vue.component('自定义的组件名', {
template:`
<div>
<button @click='send'>按钮</button>
</div>
`,
methods:{
send(){
this.$emit('自定义事件名', data)
}
}
})
// 在字符串模板中 直接 通过 $emit()触发
Vue.component('自定义的组件名', {
template:`
<div>
<button @click="$emit('自定义事件名', data)">按钮</button>
</div>
`,
})
- 监听事件: 在组件标签上 通过 v-on监听自定义事件
v-on:自定义事件名='父组件中的methods中的方法'
;
父组件中必须存在对应的方法
// 通过绑定父组件中的方法名
<组件标签名 v-on:自定义事件名='父组件中methods中的方法'></组件标签名>
// 直接在组件标签上进行事件处理 通过 $event 事件对象获取数据
<child v-on:changefontsize='fontSize += $event'></child>
- 完整的代码
<div id="app">
<p :style="{fontSize:fontSize + 'px'}">hello world</p>
<!-- <child v-on:changefontsize='fontSize += $event'></child> -->
<child v-on:changefontsize='changeFont'></child>
</div>
<script src="./js/vue.js"></script>
<script>
Vue.component('child', {
template:`
<div>
<button @click='$emit("changefontsize", 1)'>方法字体 实现方式1</button>
<button @click='changeFont'>方法字体 实现方式2</button>
</div>
`,
methods:{
changeFont(){
// 实现方式2
this.$emit("changefontsize", 1)
}
}
})
const app = new Vue({
el:'#app',
data:{
fontSize:20
},
methods:{
changeFont(data){
this.fontSize += data;
}
}
})
</script>
vue的插槽
插槽概念
vue提供了一套内容分发机制的API,将 元素作为承载分发内容的出口。 就是插槽
插槽的分类
- 默认插槽
- 具名插槽
- 作用域插槽
默认插槽
<slot>
标签用于组件模板内
- 定义一个默认插槽
const child = {
template:`
<div>
<slot></slot>
</div>
`
}
- 内容分发 : 在组件标签内使用
<组件标签>
<template>
分发的内容
</template>
</组件标签>
具名插槽
给 <slot>
标签添加一个name属性, 自定义插槽的名字,<slot name='自定义插槽名'></slot>
- 定义具名插槽
const child = {
template:`
<div>
<slot></slot>
<slot name='自定义插槽名'></slot>
</div>
`
}
- 使用具名插槽
必须结合 v-slot 指令 绑定插槽, v-slot指令只能用于 template 标签上(vue内置的标签)
<组件标签>
<template v-slot:自定义插槽名>
分发的内容 具名插槽
</template>
<template v-slot:default>
分发的内容 默认插槽
</template>
</组件标签>
作用域插槽
本质是用来传递数据
- 定义一个作用域插槽
// value 就是传递的数据
const child = {
template:`
<div>
<slot 自定义属性名1='value1' 自定义属性名2='value2'></slot>
<slot name='自定义插槽名' 自定义属性名1='value1' 自定义属性名2='value2'></slot>
</div>
`
}
- 使用作用域插槽: 接受数据
接受数据 通过 带表达式的v-slot 指令进行接受,v-slot='自定义名字'
, 可以用任何你喜欢的名字进行接受, 接受的结果是一个对象集合, 包含了所有的数据
<组件标签>
<template v-slot='自定义名字'>
分发的内容 默认插槽
</template>
<template v-slot:自定义插槽名='自定义名字'>
分发的内容 具名插槽 自定义属性名 对应的是slot标签上的自定义属性名
{{通过自定义名.自定义属性名}}
</template>
</组件标签>
插槽的默认值
定义插槽是可以给插槽提供默认值(后备内容); 如果没有提供具体的值,会显示默认值, 如果提供了具体的值,则会替换默认值
const child = {
template:`
<div>
<slot>默认值</slot>
<slot name='自定义插槽名'></slot>
</div>
`
}
v-slot指令的简写
v-slot:自定义插槽名
可以进行简写, v-slot:
整体简写 为 #
, #自定义插槽名
组件标签和HTML标签的区别
- 标签上属性的区别
- 组件标签上添加属性(自定义属性)意味着是数据传递,需要在组件模板内 通过 prop 接受
- html标签上添加属性 就是标签的属性
- 绑定事件的区别
- HTML标签上绑定的事件是原生事件
- 组件标签上绑定的事件都是自定义事件,需要通过
this.$emit()
进行触发
- 标签内添加内容
- html标签内添加内容就是标签的内容
- 组件标签内添加内容,如果没有
<slot></slot>
标签存在,则会被忽略,如果<slot></slot>
标签存在,则是进行内容分发
生命周期钩子函数
- beforeCreate() : 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
- created() : 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),property 和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el property 目前尚不可用。
- beforeMount() : 在挂载开始之前被调用:相关的 render 函数首次被调用
- mounted() :实例被挂载后调用,这时 el 被新创建的 vm. e l 替 换 了 。 如 果 根 实 例 挂 载 到 了 一 个 文 档 内 的 元 素 上 , 当 m o u n t e d 被 调 用 时 v m . el 替换了。如果根实例挂载到了一个文档内的元素上,当 mounted 被调用时 vm. el替换了。如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.el 也在文档内。
- beforeUpdate() : 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器
- updated() :由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
- beforeDestroy() : 实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed() :实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
动态组件
生命周期: 结合 kepp-alive 组件使用:
- activated : 被 keep-alive 缓存的组件激活时调用。
- deactivated : 被 keep-alive 缓存的组件停用时调用。
动态组件 : component 内置标签 结合 is 属性 实现动态组件
// 绑定静态的组件
<component is='组件名'></component>
// 绑定动态组件
<component v-bind:is='data中的key'></component>
// 针对于动态组件,可以结合 kepp-alive 实现组件的缓存
<keep-alive>
<component v-bind:is='data中的key'></component>
</keep-alive>