56-61 组件插槽动态组件,异步组件

Posted 卷毛崽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了56-61 组件插槽动态组件,异步组件相关的知识,希望对你有一定的参考价值。

插槽的基本使用


先写一个组件,然后将按钮注释,改为插槽,其中插槽可以编写默认内容,在应用组件时,将自定义元素写在组件中,就会替换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>

效果:隔一段时间加载,模拟服务器渲染

以上是关于56-61 组件插槽动态组件,异步组件的主要内容,如果未能解决你的问题,请参考以下文章

九动态组件与插槽

九动态组件与插槽

Vue入门基础—— 动态组件&插槽&自定义指令

Vue入门基础—— 动态组件&插槽&自定义指令

Vue动态组件 & 插槽 & 自定义指令

:动态组件,插槽,自定义指令