创建vue的两种方式
vue create cli-demo // 基于webpack打包
npm init vue@latest // 基于vite打包
配置别名(掌握)
组件嵌入(重要)
组件通信(重要)
父传子
props数组类型:
- 不能对类型进行验证
- 没有默认值
常用方式:
重要的原则:对象类型写默认值,需编写default的函数,函数返回默认值
age:{
type:Number,
default: () => ({age:100})
},
height:{
type:String,
default: () => ['aa','bb']
}
type的类型都可以是哪些:
String Number Boolean Array Object Date Function Symbol
子传父
<script>
export default {
name: 'AddCounter',
emits:['add'], // 注册说明
methods:{
btnClick(num) {
this.$emit('add',num)
}
}
}
</script>
案例练习
子组件
<template>
<div class="tab-control">
<template v-for="(item,index) in titles" :key="item">
<div class="tab-control-item"
@click="itemClick(index)"
:class="{active: index === currentIndex}">
<span>{{ item }}</span>
</div>
</template>
</div>
</template>
<script>
export default {
name: "TabControl",
props: {
titles: {
type: Array,
default: () => {
}
}
},
data() {
return {
currentIndex: 0
}
},
emits:['tabItemClick'],
methods: {
itemClick(index) {
this.currentIndex = index
this.$emit('tabItemClick',index)
}
}
}
</script>
<style scoped>
.tab-control {
display: flex;
height: 44px;
line-height: 44px;
text-align: center;
}
.tab-control-item {
flex: 1;
}
.active {
color: red;
font-weight: 700;
}
.active span{
border-bottom: 3px solid red;
padding: 8px;
}
</style>
父组件
<template>
<div class="app">
<TabControl :titles="['衣服','鞋子','包包']" @tab-item-click="tabItemClick"/>
<h1>{{pageContents[currentIndex]}}</h1>
</div>
</template>
<script>
import TabControl from "./TabControl.vue";
export default {
name: 'App',
components: {TabControl},
data() {
return {
pageContents:['衣服页面','鞋子页面','包包页面'],
currentIndex:0
}
},
methods:{
tabItemClick(index){
this.currentIndex = index
}
}
}
</script>
非父子通信 (了解)
- 全局事件总线 (掌握)
Vue3官方有推荐一些库,例如 mitt 或 tiny-emitter
安装这个库:npm install hy-event-bus
- Provide/Inject (了解 )
插槽Slot(掌握)
默认插槽
具名插槽
具名插槽缩写: v-slot: 替换为字符 #
<NavBar>
<template #left>
<button>返回</button>
</template>
<template #center>
<span>内容</span>
</template>
<template #right>
<a href="#">登录</a>
</template>
</NavBar>
作用域插槽(理解)
-
插槽是默认插槽default,那么
v-slot:default="slotProps"可以简写为v-slot="slotProps" -
插槽只有默认插槽时,组件的标签可以被当做插槽的模板来使用
生命周期 (重要)
beforCreate: 创建组件实例对象
created: template模板编译 ( 发送网络请求、事件监听、this.$wach() )
beforeMount: 挂载到虚拟DOM,根据虚拟DOM生成真实DOM,界面可以看到div
mounted: 数据更新,数据发生改变 ( 获取并使用DOM )
beforeUpdate: 根据最新的数据生成VNode,再生成新的虚拟DOM,根据虚拟DOM生成真实DOM
updated: 更新完成,回调updated
beforeUnmount: 组件不再使用,将之前挂载在虚拟DOM中的VNode从虚拟DOM中移除
unmountd: 移除完毕,将组件实例销毁 ( 取消事件监听、回收操作 )
beforeCreate() {
console.log('beforeCreate:组件被创建之前');
},
created() {
console.log('created: 组件被创建完成');
},
beforeMount() {
console.log('beforeMount: 组件准备被挂载');
},
mounted() {
console.log('mounted: 组件被挂载 虚拟DOM -> 真实DOM');
},
beforeUpdate() {
console.log('beforeUpdate: 数据发生改变,准备更新DOM');
},
updated() {
console.log('updated: 已经更新');
},
beforeUnmount() {
console.log('beforeUnmount: 准备卸载DOM元素(卸载之前)');
},
unmounted() {
console.log('unmounted: DOM元素被卸载完毕');
}
$refs获取元素或子组件实例 (掌握)
可以通过$parent来访问父元素
可以通过$root来访问根组件
动态组件案例 (了解)
keep-alive (理解)
某些情况我们希望继续保持组件的状态,而不是销毁掉,就可以使用一个内置组件:keep-alive
就不会频繁调用 created和 unmounted
include可以用逗号分隔字符串、正则表达式或一个数组来表示
希望监听何时进入、离开了组件;可以使用 activated 和 deactivated 这两个生命周期钩子函数监听
// keep-alive组件进入活跃状态,监听有没有切换
activated() {
console.log('activated,回来');
},
deactivated() {
console.log('deactivated,离开');
}
Webpack的代码分包
组件之间是通过模块化直接依赖的,webpack在打包时会将组件模块打包到一起(比如app.js文件中),随着项目的不断庞大,app.js文件的内容过大,会造成首屏的渲染速度变慢
打包时,对于一些不需要立即使用的组件,可以单独对它们进行拆分成一些小的代码块chunk.js,这些chunk.js会在需要时从服务器加载下来,并且运行代码,显示对应的内容
对某个组件进行单独打包
import {defineAsyncComponent} from "vue";
const AsyncCategory = defineAsyncComponent(() => import('./views/Category.vue'))
components: {Home, About, Category:AsyncCategory},
组件的v-model (理解)
mixin 混入 (了解)
如果是data函数的返回值对象
- 返回值对象默认情况下会进行合并
- data返回值对象的属性发生了冲突,那么会保留组件自身的数据
如果生命周期钩子函数
- 生命周期的钩子函数会被合并到数组中,都会被调用
值为对象的选项(methods、components、directives),将被合并为同一个对象
- 比如都有methods选项,并且都定义了方法,那么它们都会生效
- 但是如果对象的key相同,那么会取组件对象的键值对;
全局混入
createApp(App).mixin({
created() {
console.log('mixin create');
}
}).mount('#app')