切换组件案例
不再使用v-if,而是使用动态组件来实现组件之间的切换。因为动态组件的:is="组件名",会更加的高效。通过:is的值,来决定具体组件页面。
App.vue
<template>
<div>
<button v-for="(item,index) in tabs"
:key = item
@click="itemClick(item)"
:class="{active:currentTab === item}"
>{{item}}</button>
//动态组件的一个特殊值 :is 可以用来决定显示什么组件
// :is="home" 表示 显示home组件
<component :is = "currentTab"
></component>
//1.动态组件传数据
<component
:is="currentTab"
name="coderwhy"
:age="18"
//3.做出emit操作
@pageClick="pageClick"
>
这里age加上v-vind就是一个表达式,也就是number类型的,不加v-bind,就是一个字符串
</component>
</div>
</template>
<script>
import Home from
import About from
import Category from
export default{
components:{
Home,
About,
Category,
},
data(){
return{
tabs:["home","about","catagory"]
currentTab:"home"
}
},
methods:{
itemClick(item){
this.currentTab = item;
},
pageClick(){
console.log("内部发生点击")
}
}
}
</script>
<style scoped>
.active{
color:red;
}
</style>
about.vue
<template>
<div>
About.vue
</div>
</template>
<script>
import
export default{
components:{
}
}
</script>
home.vue
<template>
<div @click="divClick">
//这里就可以接收到App.vue的动态组件传来的数据
{{name}}--{{age}}
</div>
</template>
<script>
import
export default{
props:{
name:{
type:String
},
age:{
type:Number
}
},
//1.声明触发事件
emits:["pageClick"],
methods:{
divClick(){
//2.当我触发Home.vue的divClick的时候,我要求你App.vue也要做出相应的操作
this.$emit("pageClick")
}
}
}
</script>
category.vue
<template>
<div>
category.vue
</div>
</template>
<script>
import
export default{
components:{
}
}
</script>
1.我首先将子组件局部注册,然后使用动态组件<component :is="currentTab" name="coderwhy" :age="18" @homeClick="homeClick" >来将我父组件中的attributes属性传输给子组件,而不是和以前一样,定义在div中然后传数据,高级了。
2.然后我子组件和以前一样用props接收父组件传来的数据。
3.我在子组件中emits给父组件,此时父组件的component动态组件标签上可以写emits来的方法,此后,我只需要在父组件上,点击子组件的组件,就可以传输数据给子组件,如下:我点Home组件:coderwhy-18,就会触发方法
不推荐v-if的
keep-alive
上述讲到的方法虽然能够实现了动态组件的切换,但是每次切换都会把上一个组件销毁,然后渲染下一个组件,对于多次切换而言,显然每次的销毁和重新渲染,很大消耗了我们的性能。所以我们可以通过keep-alive对组件进行缓存,对于不显示的组件不是去销毁他,而是使他处理不激活的状态,当需要显示时再去激活。
对组件进行包裹即可
keep-alive属性
include="..",include的值,需要在对应组件中,书写name书写,才能匹配
max:设置最多缓存组件的数量。会将最近没有被访问的实例,优先销毁。
name:不写的话,默认全部缓存,max不写,默认全部缓存
缓存组件的生命周期
就是我从其他地方切入进来的时候,活跃的生命周期函数会触发,离开的时候也会触发不活跃的生命周期函数,方便我们在里面做出操作。
Webpack的代码分包
我们基于Vue CLI打包,CLI基于Webpack打包,所以最终还是依赖Webpack打包。
一个代码依赖一个模块,模块又依赖模块,webpack会将所依赖的全部一起打包,当过多的时候,就会造成打包后的静态资源,过于复杂,最终造成过首屏的渲染速度。
所以我希望将他打包到单独的一个包里,浏览器打开时可能不需要用到那个包,在后期不忙的时候再使用,这样在首屏渲染的时候会加快一点。
import {sum} from '...'
不管我写了多少,我都会被打包到dist/js/app.js中
所以我希望把一些特定的包,打包到指定的文件夹里
通过import函数导入的模块,后续webpack对其进行打包的时候就会进行分包的操作
import("上方sum的文件夹").then((res)=>{
console.log(res.sum(20,30))
})
新包:chunk-哈希值.js/map,该包:表示我请求的时候会先不请求他,后续才会使用,提高首屏渲染速度
Vue中实现异步组件
AsyncCategory.vue
<template>
<div>
我是AsyncCategory.vue
</div>
</template>
<script>
export default{
components:{
}
}
</script>
App.vue
<template>
<div>
<async-category/>
</div>
</template>
<script>
import { defineAsyncComponent } from 'vue'
//使用组件,但是不希望组件后期打包放在一块
//变成了异步组件,到时候打包就会被打包到单独包里
//1.工厂函数写法
const AsyncCategory = defineAsyncComponent(
()=>{
import("./AsyncCategory.vue")
})
//2.对象写法,可以传更多属性
const AsyncCategory = defineAsyncComponent({
loader:()=>import("./AsyncCategory.vue")
loadingComponent:Loading
是一个组件,还在加载时候占位,先显示某个组件
errorComponent:加载失败的时候,显示这个组件
delay:延迟多久才显示组件,单位毫秒
onError:function(err,retry,fail,attempts){
err:错误信息对象
retry:函数,调用retry尝试重新加载
fail:函数,指示加载程序结束退出
attempts:允许最大重试次数
}
})
export default{
components:{
AsyncCategory
}
}
</script>
Loading.vue
<template>
<div>
我是Loading.vue,占位的
</div>
</template>
<script>
import
export default{
components:{
}
}
</script>
异步组件和Suspense
App.vue
<template>
<div>
<suspense>
<template #default>
<async-category>
</async-category>
</template>
//如果我default插槽没有的话,就显示fallback的
<template #fallback>
<loading>
</loading>
</template>
</suspense>
</div>
</template>
<script>
import { defineAsyncComponent } from 'vue'
//使用组件,但是不希望组件后期打包放在一块
//变成了异步组件,到时候打包就会被打包到单独包里
//1.工厂函数写法
const AsyncCategory = defineAsyncComponent(
()=>{
import("./AsyncCategory.vue")
})
export default{
components:{
AsyncCategory,
loading,
}
}
</script>
$refs的使用
意思就是:想拿到DOM元素,别用DOM操作(getElementById())
引用元素和组件(父用子) App.vue
<template>
<div>
//绑定到元素上
<h2 ref="title">哈哈</h2>
//绑定到组件实例
<nav-bar ref="navBar"></nav-bar>
<button @click="btnClick"></button>
</div>
</template>
<script>
export default{
import NavBar from './NavBar.vue'
methods:{
btnClick(){
//this.$refs可以拿到所有注册过ref的元素对象
console.log(this.$refs.title)
//实质是一个Proxy对象,不影响
console.log(this.$refs.navBar.message)
this.$refs.navBar.sayHello()
}
},
components:{
NavBar,
}
}
</script>
NavBar.vue
<template>
<div>
</div>
</template>
<script>
import
export default{
data(){
return:{
message:"Hello"
}
},
methods:{
sayHello(){
console.log("Hello")
}
}
}
</script>
root
NavBar.vue
<template>
<div>
<button @click="getParentAndRoot"></button>
</div>
</template>
<script>
import
export default{
data(){
return:{
message:"Hello"
}
},
methods:{
sayHello(){
console.log("Hello")
},
getParentAndRoot(){
//拿到父组件的数据
this.$parent
//拿到根组件(这里就是App.vue)的数据
this.$root
}
}
}
</script>
App.vue拿到组件根元素
this.$refs.navBar.$el
认识生命周期
组件的生命周期
Home.vue
<template>
<div>
{{message}}
<button @click="changeMessage">更新</button>
</div>
</template>
<script>
export default{
data(){
return:{
message:"Hello"
}
},
methods:{
changeMessage(){
this.message="啊"
}
}
beforeCreate(){
},
created(){
},
beforeMount(){
},
mounted(){
},
beforeUnmount(){
},
Unmounted(){
},
beforeUpdate(){
},
updated(){
},
}
</script>
App.vue
<template>
<div>
<button @click="isShow = !isShow">切换实验 卸载
</button>
<template v-if="isShow">
<home>v-if=false时,会直接卸载组件</home>
</template>
</div>
</template>
<script>
import Home from '...'
export default{
components:{
Home
},
data(){
return:{
isShow:true
}
},
}
</script>
组件的v-model
一开始显示的是Hello,点击btn后变成了123
HyInput.vue
<template>
//2.并且书写一个方法,当子组件触发的时候,也要让父组件触发
<div>
<button @click="btnClick"></button>
</div>
</template>
<script>
export default{
//父组件使用了v-model,1.子组件需要定义props接收modelValue
props:{
modelValue:String
},
methods:{
btnClick(){
this.$emit("update:modelValue","123")
}
},
emits:['update:modelValue']
}
</script>
App.vue
<template>
<div>
//组件上使用v-model
<hy-input v-model="message"></hy-input>
</div>
</template>
<script>
import
export default{
components:{
HyInput,
},
data(){
return:{
message:"Hello"
}
}
}
</script>
不要乱改props中的值
自定义表单事件
HyInput.vue
<template>
//2.并且书写一个方法,当子组件触发的时候,也要让父组件触发
<div>
我App里写了两个v-model,我这里可以写两个input
<input v-model = "value"/>
<input v-model = "title-model"/>
</div>
</template>
<script>
export default{
//父组件使用了v-model,1.子组件需要定义props接收modelValue
props:{
modelValue:String,
title:String,
},
emits:['update:modelValue','update:title'],
computed:{
value:{
set(value){
this.$emit
("update:modelValue",value)
},
get(){
return this.modelValue
},
},
title-model:{
set(title){
this.$emit
("update:title",title)
},
get(){
return this.title
},
}
}
}
</script>
注:
<hy-input v-model="message">等价于
<hy-input :modelValue="message"
@update:model-value="message"=$event>
App.vue
<template>
<div>
//组件上使用v-model,我希望我父组件里的值,子组件修改,父组件也能同步变化
<hy-input
v-model="message"
//使用多个v-model的时候,给他传值的形式才行
v-model:title="title"></hy-input>
</div>
</template>
<script>
import
export default{
components:{
HyInput,
},
data(){
return:{
message:"Hello",
title:"哈哈哈"
}
}
}
</script>