vue基础3-组件
- 组件
- 动态组件
- 插槽
- 自定义指令
组件
什么是项目的组件化开发?
根据封装的思想,把页面上可复用的UI结构封装成组件,方便项目的开发与维护;
Vue 中规定:组件的后缀名为.vue;
1、组件的三个 组成部分
- template
- script
- style
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return {
msg:'hello'
}
}
}
</script>
<style scoped lang="less">
h1 {
margin: 40px 0 0;
}
</style>
【注意】
- 组件中data数据源不能是一个对象,必选是一个函数;
- return{}一个对象,数据都在{}里面
- 在组件中,this指向组件实例;
- 组件的模版结构中,只能有一个根节点;template中必须只有一个根元素包裹内容;
原因是:
- a 组件中data如果是一个对象,a组件在复用时,其他组件在修改数据时,那么用了a组件的其它组件都会改变;会造成数据混乱;
- a 组件中data如果是一个函数,组件会有自己独立的数据源空间,不会受其他组件数据的影响;
【less】
如何启用 less 语法?
<style scoped lang="less">
</style>
- 当在 style 标签中定义了 lang=“less”,就可以使用less语法了;
- 当在 style 标签中定义了 scoped 时,style 标签中的所有属性就只作用于当前组件的样式,实现组件样式私有化,从而也就不会造成样式全局污染
2、使用组件的三个步骤
组件之间的父子关系:
- 组件在被封装好之后,彼此之间是相互独立的,不存在父子关系;
- 在使用组件时,根据彼此的嵌套关系,才有了父子关系,兄弟关系;
定义 Left.vue,Right.vue,app.vue三个组件;
需求 把left.vue组件放到app.vue组件中;
使用组件的三个步骤:
- 导入 import Left from ‘Left.vue’;
- 注册 使用components节点注册
- 使用 在模版语法中,以标签形式使用刚才注册的组件;
1、导入
import Left from '@/components/Left.vue';
2、注册
export default{
name:'App',
components:{
//注册
Left
}
}
3、使用
<template>
<div>
<Left></Left>
</div>
</template>
注册全局组件
- 在components 节点下的组件注册属于私有组件;
- 在vue项目的main.js入口文件中,通过Vue.components()方法,可以注册全局组件;
main.js
import Left from '@/components/Left.vue';
Vue.components('MyLeft',Left);
使用
<template>
<MyLeft></MyLeft>
</template>
两个参数
- 第一个参数是字符串形式,表示组件的"注册名称”
- 第二个参数是要被注册 的组件
组件的props属性
组件的props属性,可以提高组件的复用性;
props 是自定义属性,允许使用者通过自定义属性值,为当前组件定义初始值;
语法:
export default {
name: "Count",
props:['init'],
data(){
return{}
}
}
使用
<template>
<MyCount :init="5"></MyCount>
</template>
【注意】
- init=“5”, init是属性,5是字符串
- :init=“5”,v-bind绑定init属性,5是数值型
props 是只读的
-
vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错
-
要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!
export default {
name: "Count",
props:['init'],
data(){
return{
count:this.init //把init的值转存到count
}
}
}
</script>
props 的默认值default
在声明自定义属性值时,可以使用 default 来定义属性的默认值;
在没有定义初始值时,默认值生效;
props:{
init:{
default:66
}
},
props 的type值类型
用type属性定义值的类型,如果传的值不一致,会报错;
props:{
init:{
default:66,
type:Number
}
},
props 的required必填项
init 值必传,否则会报错;
required:true;必填项校验;
props:{
init:{
default:66,
type:Number,
required:true
}
},
动态组件
1、什么是动态组件?
指的是动态切换组件的显示和隐藏;
2、如何实现动态组件的渲染?
vue提供了一个内置的 Compoent 组件,专门用来实现动态组件的渲染和隐藏;
vue提供了一个内置的keep-alive组件,专门用来实现动态组件的缓存;
keep-alive组件对应的生命周期函数:
组件被激活时,对应的生命周期函数 activated();
组件被缓存时,对应的生命周期函数 deactivated();
当组件第一次被创建时,触发生命周期函数 created,activated;
当组件被激活时,触发生命周期函数 activated();
keep-alive 的属性:
- keep-alive 的 include 属性:定义被缓存的组件;
- keep-alive 的 exclude 属性:指定不被缓存的组件;
- 不建议同时使用 include,exclude属性;
<h4>动态组件的学习</h4>
<button @click="comName='First'">展示First</button>
<button @click="comName='Second'">展示Second</button>
<div class="box-active">
<keep-alive include="First,Second">
<component :is="comName"></component>
</keep-alive>
</div>
插槽
1、什么是插槽?
允许开发者在封装组件的时候,把不确定的,希望被用户指定的部分定义为插槽;
1、插槽的简单使用:
提供插槽的组件:
<template>
<div class="hello">
<h4>插槽</h4>
<hr>
<slot></slot>
</div>
</template>
使用插槽的组件
<HelloWorld>
<p>555555555555555555555</p>
</HelloWorld>
【注意】
- 如果没有slot标签,组件当中p标签就不会渲染
- 每一个 slot 标签,都有一个name属性,不写默认是default;
如果有多个插槽,怎么把内容渲染到指定的插槽内部呢?
提供插槽的组件:
<template>
<div class="hello">
<h4>插槽</h4>
<hr>
<slot name="default"></slot>
<slot name="box"></slot>
</div>
</template>
使用插槽的组件
<HelloWorld>
<template v-slot:default>
<p>555555555555555555555</p>
</template>
</HelloWorld>
【注意】
- 语法:v-slot:default;
- 简写: #default
- v-slot指令不能直接用在元素身上,必须用在template元素上 ;
- template 标签是一个虚拟标签,只起到包裹元素的作用,不会被渲染成HTML元素
2、具名插槽
指的就是给每一个插槽都起一个名字,这样就可以指定插槽渲染内容了;
3、作用域插槽
给插槽定义一个属性;
如果父组件想要使用插槽的值,通过插槽名就可以接收;
<slot name="box" msg="hello world"></slot>
<template v-slot:box="obj">
<p>指定渲染到某个插值</p>
<p>{{obj.msg}}</p>
</template>
接收一个对象
//子组件 helloWorld.vue
<slot name="box" msg="hello world" :user="userinfo"></slot>
data(){
return{
userinfo:{
"name":"zhangsan",
"age":5
}
}
}
//父组件app.vue
<HelloWorld>
<template v-slot:box="obj">
<p>指定渲染到某个插值</p>
<p>{{obj}}</p>
<p>{{obj.msg}}</p>
<p>{{obj.user}}</p>
</template>
</HelloWorld>
// 结构赋值
<HelloWorld>
<template v-slot:box="{msg,user}">
<p>指定渲染到某个插值</p>
<p>{{msg}}</p>
<p>{{user}}</p>
</template>
</HelloWorld>
自定义指令
vue 提供了一些内置指令如v-on,v-bind等,还可以自定义指令:
- 私有自定义指令
- 全局 自定义指令
私有自定义指令
在每一个 vue组件中,可以在 directives节点下定义私有自定义指令:
//私有自定义指令
directives:{
//定义名为color的指令,指向一个对象
color:{
bind(el){
el.style.color='red'
}
}
}
//使用
<p v-color>自定义指令</p>
【注意】
- 当指令第一次绑定到元素上时,会立即触发bind()函数;
- el参数指的是绑定的DOM元素
<p v-color="color">自定义指令</p>
<p v-color="'red'">自定义指令</p>
data(){
return{
color:"blue"
}
},
//私有自定义指令
directives:{
//定义名为color的指令,指向一个对象
color:{
bind(el,binding){
el.style.color= binding.value;
}
}
}
update函数
<p v-color="color">自定义指令</p>
<p v-color="'red'">自定义指令</p>
<button @click="color='yellow'"> 点击更换文本颜色</button>
//私有自定义指令
directives:{
//定义名为color的指令,指向一个对象
color:{
//在元素第一次绑定指令时,触发bind函数
bind(el,binding){
el.style.color= binding.value;
},
//当DOM元素更新时,触发update函数
update(el,binding){
el.style.color= binding.value;
}
}
}
函数简写
如果bind和 update函数中有相同的逻辑,则对象格式的自定义指令可以写成 函数形式;
//私有自定义指令
directives:{
//定义名为color的指令,指向一个对象
color(el,binding){
el.style.color= binding.value;
}
}
全局自定义指令
Vue.directive('color',function(el,binding){
el.style.color= binding.value;
})