组件化开发
- 一个页面(.vue文件)可能有一个或多个组件(.vue)组成完整的页面功能
封装的思想:把页面上
可重用的部分
封装为组件
,从而方便项目的 开发 和 维护vue组件-封装创建
哪部分标签复用, 就把哪部分封装到组件内
- 组件内template只能有一个根标签
- 组件内data必须是一个函数, 独立作用域
- 封装路径:components/Pannel.vue
```vue
芙蓉楼送辛渐
{{ isShow ? ‘收起’ : ‘展开’ }}寒雨连江夜入吴,
平明送客楚山孤。
洛阳亲友如相问,
一片冰心在玉壶。
<a name="gIjef"></a>
### vue组件-复用
全局注册语法:<br />全局入口在main.js, 在new Vue之上注册<br />`import 组件对象 from 'vue文件路径'`<br />`Vue.component("组件名", 组件对象)`
- 组件名和组件对象使用大驼峰命名
```javascript
import PannelTest from './components/pannel.vue'
Vue.component('Pannel', PannelTest)
在页面中使用:
- 单闭合:
<组件名 />
- 双闭合:
<组件名> <组件名 />
```vue
局部导入语法:<br />`import 组件对象 from '文件路径'`<br />`components: { 组件名: 组件对象 }`(跟data同级)
- components对象中,键值对一样可以只写一个
- 组件名和组件对象使用大驼峰命名
在页面中使用:
- 单闭合:`<组件名 />`
- 双闭合:`<组件名> <组件名 />`
```vue
<template>
<div>
<Pannel />
</div>
</template>
<script>
import Pannel from '../components/pannel.vue'
export default {
components: {
Pannel: Pannel
}
}
</script>
<style lang="less" scoped>
</style>
vue组件-scoped作用
- 问题:组件化开发中,父子嵌套情况,样式会出现类名冲突时
- 说明:父组件的样式会覆盖子组件的样式
- 解决:在每个
style
标签中加入scoped
属性 -
vue组件-/deep/深度作用选择符
问题:父元素控制子元素的样式时,开启了样式模块化
scoped
就控制不到- 解决:在要控制的子组件类名或元素名前面加一个
/deep/
(深度作用选择符) - 默认子组件的根元素,会带上父组件的data-v-hash属性,所以可以直接控制
vue组件通信(重点)
vue单向数据流(限制)
- 保护数据的可维护性(只在一个位置可以修改数据)
- 父组件传递的数据
props
,不能改,props只读 - 只有父组件可以改
- 简单类型的 不能直接改
- 引用类型的 不能改地址,但是可以修改里面的值(部分改)
- 总结:在哪儿定义就在那儿改
父传子-props
- 在父组件中的子组件标签
:传递的数据名="data变量名"
- 不加:传递的是固定值,加:必须传递变量
- 子组件中接收:
props: ['父组件传递的数据名']
- 实际开发使用
props: {
父组件转递的数据名: {
type:设置(校验)接受数据的类型
default: ( ) => { return }
}
}
default是默认属性如果父组件没有传递数据,使用这个默认值
如果是复杂类型(对象,数组)的,默认值需要通过函数返回默认值
export default {
props: {
tabList: {
type: Array,
default: () => [],
require: true // 表示必须传递,不传递会报错
},
},
}
子传父
在父组件中的子组件标签 @自定义事件="methods函数"
修改在父组件methods函数的内部修改
子组件的methods函数内部 this.$emit('自定义事件',参数1,参数2)
传递的参数会传递给自定义事件绑定的函数
组件生命周期
阶段
- 初始化 => 创建组件
- 挂载 => 渲染显示组件
- 更新 => 修改数据
-
钩子函数
初始化:(只执行一次,.vue文件实例化)
- 创建前:
beforeCreate ( ) { 实例化前 }
- 创建后:
created ( ) { 发送ajax请求 }
- 创建前:
- 挂载:(只执行一次,页面渲染)
- 挂载前:
beforeMounte () { 页面渲染前,不能操作dom }
- 挂在后:
mounted () { 可以操作dom和发送ajsx请求 }
- 挂载前:
- 更新:(可以执行多次,data变量更新)
- 更新前:
beforeUpdate () { 数据更新,页面没有更新 }
- 更新后:
updated () { 数据更新,页面更新 }
- 更新前:
- 销毁:(只执行一次,切换页面或者组件从页面中被移除)
- 销毁前:
beforeDestroy () { 清除定时器,解绑js事件 }
- 销毁后:
destroyed () { 清除定时器,解绑js事件 }
- 销毁前:
ref和$refs的使用
获取DOM对象
- 在获取DOM的元素身上写
ref属性并赋值
- 通过
this.$refs.ref属性值
获取DOM对象 - 通过
this.$refs.ref属性值.style.css属性
操作dom
获取组件实例
- 在获取组件的自定义标签身上写
ref属性并赋值
- 通过
this.$refs.ref的属性值
获取组件实例 this.$refs.ref的属性值 === 获取当前的组件实例this
$nextTick使用
语法:
this.$nextTick( () => {})
vue修改data变量后,不能立马获取最新的dom (获取上一次的dom)
- vue做了优化,dom的更新是异步的
- 获取异步更新之后的dom使用
this.$nextTick(callback回调函数)
- callback函数内部就可以获取到最新的dom
- 可以使用
async``await this.$nextTick()
的写法
动态组件
语法:<component :is="data变量"><component>
- data变量值为动态切换组件的标签名
- 可以动态切换多个子组件
```vue
```vue
<template>
<div>
<div class="box">
<p>登录页面</p>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.box {
border: 2px solid pink;
background-color: skyblue;
}
</style>
<template>
<div class="box">
<p>注册页面</p>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.box {
border: 2px solid skyblue;
background-color: pink;
}
</style>
组件缓存
现象:动态切换的组件,切换时会被销毁每次都会被重新创建(浪费性能)
语法:<keep-alive><keep-alive>
- 包裹后组件只会在第一次被创建一次,之后会被缓存
- 缓存的生命周期
- 激活:
activated() { }
- 失去激活状态:
deactivated() { }
- 激活:
- include属性
include="被缓存组件的name值"
- nama值是唯一的(不能使用html元素名,会报错)
```vue
```vue
<template>
<div>
<div class="box">
<p>登录页面</p>
</div>
</div>
</template>
<script>
export default {
name: 'lg',
deactivated () {
console.log('离开了缓存')
},
activated () {
console.log('进入了缓存')
},
created () {
console.log('创建了组件')
},
destroyed () {
console.log('被销毁了')
},
}
</script>
<style scoped>
.box {
border: 2px solid pink;
background-color: skyblue;
}
</style>
<template>
<div class="box">
<p>注册页面</p>
</div>
</template>
<script>
export default {
name: 'rg'
}
</script>
<style scoped>
.box {
border: 2px solid skyblue;
background-color: pink;
}
</style>
组件插槽
通过组件标签传递内容给子组件,子组件通过slot元素接收展示渲染
默认插槽
语法:
传递<组件标签>插槽内容</组件标签>
子组件接收<solt></solt>
- solt写一个,多次写回显示重复的内容
- solt不设置内容也可以单闭合
<solt />
- 如果没有传递插槽,solt内可以设置默认值
```vue
组件插槽的使用
我是组件插槽传递的
```vue
<template>
<div>
<h2>我是子组件</h2>
<slot> <h4>插槽没传递,显示我</h4> </slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
具名插槽
语法:
传递<组件标签><template v-slot:名字>插槽内容</template></组件标签>
子组件接收<solt name="名字"></solt>
v-solt:名字
可以简写#名字
- template标签外面都属于默认插槽
- v-slot和name的名字需要一样
- 可以传递多个,name不能重复
```vue
组件插槽的使用
来自西海的 三刀 刘索隆
绿藻头,嘎嘎帅
```vue
<template>
<div>
<slot name="title"></slot>
<slot></slot>
<slot name="foot"> </slot>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
作用域插槽
语法:
传递:子组件在slot
元素上,通过动态绑定:属性名="data变量"
接收:通过<template #名字="变量">
接收传递的数据
- 传递多个变量,写多个
:属性名="data变量"
- 接收到的数据是一个对象类型,可以解构
```vue
组件插槽的使用
- {{ obj.name }}
- {{ obj.age }}
- {{ num }}
```vue
<template>
<div>
<slot name="one" :obj="obj" :num="num"> </slot>
</div>
</template>
<script>
export default {
data () {
return {
obj: { name: '张三', age: 20 },
num: 123
}
},
}
</script>
<style scoped>
</style>