56-61 组件插槽、动态组件,异步组件
插槽参考链接
https://segmentfault.com/a/1190000012996217?utm_source=tag-newest
插槽的基本使用
先写一个组件,然后将按钮注释,改为插槽,其中插槽可以编写默认内容,在应用组件时,将自定义元素写在组件中,就会替换slot的标签,十分灵活
<body>
<div id="app">
<lk-box><button>点我</button></lk-box>
<lk-box><input type="text" placeholder="输入名字"></lk-box>
</div>
<template id="box">
<div style="background-color: red; width: 200px; height: 200px;margin:20px;">
<h2>hhhh</h2>
<p>like it</p>
<!-- <button>点我</button> -->
<!-- 预留插槽 -->
<slot></slot>
</div>
</template>
<script>
const LkBox = {
template: '#box',
};
const app = Vue.createApp({
data() {
return {};
},
components: {
'lk-box': LkBox,
},
methods: {},
}).mount("#app");
</script>
</body>
<div id="app">
<lk-box><button>点我</button></lk-box>
<lk-box><input type="text" placeholder="输入名字"></lk-box>
</div>
具名插槽–v-slot
当使用多个插槽时,要有具体的命名
先按照上面的方式,写三个插槽,查看效果,分别渲染了三次很明显不对
<body>
<div id ="app">
<lk-box>
<h1>头部</h1>
<h2>主要内容</h2>
<h3>尾部</h3>
</lk-box>
</div>
<template id="box">
<div>
<p>-----</p>
<header>
<!-- 放头部 -->
<slot name="header">头部</slot>
</header>
<main>
<!-- 放内容 -->
<slot name="main">内容</slot>
</main>
<footer>
<!-- 放页脚 -->
<slot name="footer">页脚 </slot>
</footer>
<p>------</p>
</div>
</template>
<script>
const lkbox={
template:'#box'
};
const app = Vue.createApp({
data() {
return{
}
},
components: {
'lk-box':lkbox
},
methods: {}
}).mount('#app');
</script>
</body>
正确写法
主要name要一一对应,使用v-slot的指令对应子组件的插槽
<body>
<div id ="app">
<!-- 错误调用 -->
<!-- <lk-box>
<h1>头部</h1>
<h2>主要内容</h2>
<h3>尾部</h3>
</lk-box> -->
<!-- 正确的 -->
<lk-box>
<template v-slot:header>
<button>我是头部</button>
</template>
<template v-slot:main>
<input type="text" placeholder="我是中间">
</template>
<template v-slot:footer>
<button>我是尾部</button>
</template>
</lk-box>
</div>
<template id="box">
<div>
<p>-----</p>
<header>
<!-- 放头部 -->
<slot name="header">头部</slot>
</header>
<main>
<!-- 放内容 -->
<slot name="main">内容</slot>
</main>
<footer>
<!-- 放页脚 -->
<slot name="footer">页脚 </slot>
</footer>
<p>------</p>
</div>
</template>
<script>
const lkbox={
template:'#box'
};
const app = Vue.createApp({
data() {
return{
}
},
components: {
'lk-box':lkbox
},
methods: {}
}).mount('#app');
</script>
</body>
补充,默认插槽
当其中一个插槽没有命名,则当外部调用组件时,会显示的子组件中的里的内容
如果要使用外部传进来的,可以使用v-slot:default,默认对应这一个没有命名的slot进行替换
这里只黏贴了部分代码
<template v-slot:default>
<input type="text" placeholder="我是中间">
</template>
组件里的插槽未命名
<template id="box">
<div>
<p>-----</p>
<header>
<!-- 放头部 -->
<slot name="header">头部</slot>
</header>
<main>
<!-- 放内容 -->
<slot>内容</slot>
</main>
<footer>
<!-- 放页脚 -->
<slot name="footer">页脚 </slot>
</footer>
<p>------</p>
</div>
</template>
效果:
渲染作用域、作用域插槽
渲染作用域
<body>
<div id ="app">
<lk-box v-show="isshow"></lk-box>
</div>
<template id="box">
<div style="background-color: red;width: 200px;height: 200px;margin:20px">
<button>点我</button>
</div>
</template>
<script>
const lkbox={
data(){
return{
isshow:false
}
},
template:'#box'
};
const app = Vue.createApp({
data() {
return{
isshow:true
}
},
components: {
'lk-box':lkbox
},
methods: {}
}).mount('#app');
</script>
</body>
作用域插槽–使用子组件的数据
一般传入的是父组件的数据,因为作用域的问题,父子组件的数据不能随意调用,当插槽中,需要由子组件的数据进行渲染,可采用作用域插槽的方式
<body>
<div id="app">
<lk-box></lk-box>
<p>---------</p>
<lk-box>
<template v-slot:default="slotProps">
<span>{{slotProps}}</span>
<span>{{slotProps.data.join('---')}}</span>
</template>
</lk-box>
</div>
<template id="box">
<div style="background-color: red;width: 200px;height: 200px;margin:20px;">
<slot :data="nameArr">
<ul>
<li v-for="name in nameArr">{{name}}</li>
</ul>
</slot>
</div>
</template>
<script>
const lkbox = {
data(){
return{
nameArr:['张三','李四','王五']
}
},
template: "#box",
};
const app = Vue.createApp({
data() {
return {
msg: "hello",
};
},
components: {
'lk-box':lkbox
},
methods: {},
}).mount("#app");
</script>
</body>
如图1为正常调用,显示的默认插槽;现在想即调用子组件数据,并且也从父组件对插槽进行覆盖
这里slot添加data属性将子组件的数据传递出来
<slot :data="nameArr">
父组件应用时,定义一个slotProps的变量来接受子组件传过来的数组,对数据进行操作,添加----
<lk-box>
<template v-slot:default="slotProps">
<span>{{slotProps}}</span>
<span>{{slotProps.data.join('---')}}</span>
</template>
</lk-box>
动态组件
<body>
<div id="app"></div>
<script>
const app = Vue.createApp({
data() {
return {
Citem:'lk-btn'
};
},
methods: {
change(){
if(this.Citem==='lk-btn'){
this.Citem='lk-input'
}else{
this.Citem='lk-btn'
}
}
},
template:
`
<div>
第一种写法,v-show写法,控制Citem进行显示
<lk-btn v-show="Citem==='lk-btn'"></lk-btn>
<lk-input v-show="Citem==='lk-input'"></lk-input>
<p>-----</p>
<button @click="change">切换</button>
</div>
`,
});
app.component("lk-btn", {
template: `<button>点我</button>`,
});
app.component("lk-input", {
template: `<input type="text" />`,
});
app.mount("#app");
</script>
</body>
第一种方式是通过v-show动态切换
第二种是通过vue提供的动态组件,动态绑定is属性取组件,简便的实现功能,并配合keepalive避免input失活无法保存状态的问题
template: `
<div>
<keep-alive><component :is="Citem"></component></keep-alive>
<p>-----</p>
<button @click="change">切换</button>
</div>
`,
异步组件-适用于大型项目加载时
参考链接1-ES6箭头函数和普通函数的区别
参考链接2-JavaScript Promise 对象
参考链接3-ECMAScript 6 简明教程
参考链接4-VUE defineAsyncComponent函数创建异步组件
使用settimeout模拟服务器加载渲染过程,defineAsyncComponent是vue3自带的函数,用于创建异步函数,
<body>
<div id ="app">
<async-item></async-item>
</div>
<script>
const app = Vue.createApp({
data() {
return{
msg:'hello'
}
},
methods: {}
});
// 注册一个异步组件
app.component('async-item',Vue.defineAsyncComponent(()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve({
template:`<div style="width:200px;height:200px;background:red;"></div>`
})
},3000)
})
}))
app.mount('#app');
</script>
</body>
效果:隔一段时间加载,模拟服务器渲染