Vue3的动态组件和异步组价

Posted 飞鹰3995

tags:

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

今天小编在网上闲逛的时候,发现前端这几年的发展离不开组件的概念,之前小编接触到的组件,基本都是这样的

const app= Vue.createApp({
    template: `
    <input-item />
    <common-item />
        `
})

app.component(\'input-item\',{
    template: `<div>
            <input />
        </div>`
})

app.component(\'common-item\',{
    template: `<div>
            Hello World
        </div>`
})
const vm = app.mount("#root")

这个时候页面显示的一个文本框,一行文字 ,这个时候,如果我们想通过一个按钮,来切换两个元素的现实和隐藏关系,就可以把代码修改成这样

const app= Vue.createApp({
    data(){
        return {
            currentItem: \'input-item\'
        }
    },
    methods:{
        handleClick(){
            if(this.currentItem === \'input-item\'){
                this.currentItem = \'common-item\'
            }else{
                this.currentItem = \'input-item\'
            }
            // 也可以通过三目运算符来实现。还可以借鉴绑定class或者style绑定
            // this.currentItem = this.currentItem === \'input-item\'?\'common-item\':\'input-item\'
        }
    },
    template: `
    <input-item v-show="currentItem === \'input-item\'" />
    <common-item v-show="currentItem === \'common-item\'" />
    <button @click="handleClick">切换</button>
        `
})

app.component(\'input-item\',{
    template: `<div>
            <input />
        </div>`
})

app.component(\'common-item\',{
    template: `<div>
            Hello World
        </div>`
})
const vm = app.mount("#root")

有了动态组件之后,同样的需求,我们的代码就可以写成这样

// 动态组件:根据数据的变化,结合component这个标签,来随时动态切换组件的实现
const app= Vue.createApp({
    data(){
        return {
            currentItem: \'input-item\'
        }
    },
    methods:{
        handleClick(){
            if(this.currentItem === \'input-item\'){
                this.currentItem = \'common-item\'
            }else{
                this.currentItem = \'input-item\'
            }
        }
    },
    template: `
    // 为了缓存文本框之前的数据
    <keep-alive>
        <component :is="currentItem" />
    </keep-alive>
    <button @click="handleClick">切换</button>
        `
})

app.component(\'input-item\',{
    template: `<div>
            <input />
        </div>`
})

app.component(\'common-item\',{
    template: `<div>
            Hello World
        </div>`
})
const vm = app.mount("#root")

在小编的第一块代码中,都是引入自定义标签的组件之后,就可以直接展示效果,这种成为同步组件 ,当然还有异步组件,主要是为了解决首屏加载速度的问题,借助Vue3中的defineAsyncComponent,就像这样

const AsyncCommonItem = Vue.defineAsyncComponent(() => {
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve({
                template:\'<div>this is an async component</div>\'
            })
        },4000)
    })
})
const app= Vue.createApp({
    template: `
        <div>
            <common-item />
            <async-common-item />
        </div>
        `
})

app.component(\'common-item\',{
    template: `<div>
            Hello World
        </div>`
})

app.component(\'async-common-item\',AsyncCommonItem)

const vm = app.mount("#root")

当然,今天小编还为大家准备了一些其他常用的知识点,就当是饭后甜点吧
一、ref:获取DOM节点用的语法,慎用这种方法,后期维护的时候会很麻烦

const app= Vue.createApp({
    data(){
        return {
            count: 1
        }
    },
    mounted(){ // 只有早这个生命周期或者之后,将元素挂载上,才存在DOM的概念
        console.log(this.$refs.countele)  // <div>1</div>
        this.$refs.commele.sayHello()
    },
    template: `
        <div @click="count += 1">
            <div ref="countele">{{ count }}</div>
            <common-item ref=\'commele\' />
        </div>
        `
})

app.component(\'common-item\',{
    methods:{
        sayHello(){
            alert(\'hello\')
        }
    },
    template: `<div>
            Hello World
        </div>`
})

const vm = app.mount("#root")

二、privide inject:用于组件与子组件的子组件传递数据的方式

我们在通过组件向子组件的子组件传递数据的时候,可以这样

const app= Vue.createApp({
    data(){
        return {
            count: 1
        }
    },
    template: `
        <div>
            <child :count="count"/>
        </div>
        `
})

app.component(\'child\',{
    props:[\'count\'],
    template: `<div>
            <child-child :count="count" />
        </div>`
})


app.component(\'child-child\',{
    props:[\'count\'],
    template: `<div>
            {{ count }}
        </div>`
})
const vm = app.mount("#root")

显然,这样很麻烦,通过privide inject,我们可以这么写

const app= Vue.createApp({
    data(){
        return {
            count: 1
        }
    },
    // provide:{ // 不能直接调用data中的数据,需要的时候,需要写成函数的方式
    //     count:1
    // },
    // 这种是一次性的,可以通过Vue3的getter方式响应式,通过传统props一层层传递是可以
    provide(){
        return {
            count: this.count
        }
    },
    template: `
        <div>
            <child />
            <button @click="count += 1">增加</button>
        </div>
        `
})

app.component(\'child\',{
    template: `<div>
            <child-child />
        </div>`
})


app.component(\'child-child\',{
    inject:[\'count\'],
    template: `<div>
            {{ count }}
        </div>`
})
const vm = app.mount("#root")

大家还可以扫描二维码,关注我的微信公众号,蜗牛全栈

 

Vue组价的基本使用

组件是可复用的 Vue 实例,我们只需要调用就可以了。

创建组件

方法一:通过extend创建组件(不推荐)

<div id="app">
  <h2>全局组件</h2>
  <my-cpn></my-cpn>
  <h2>局部组件</h2>
  <cpnc></cpnc>
</div>

// 1.创建组件构造器对象
const cpnc = Vue.extend({
  template:`
    <div>
      <h2>标题</h2>
      <p>内容1</p>
      <p>内容2</p>
    </div>`
})
// 2.注册组件(全局组件,可以在多个vue实例中使用)
Vue.component(‘my-cpn‘, cpnc)

const app = new Vue({
  el:"#app",
  components:{//局部组件创建
    cpnc:cpnc
  }
})

方法二:template(推荐),这里有三种写法

<div id="app">
  <cpn1></cpn1>
</div>

// 1.注册全局组件语法糖
Vue.component(‘cpn1‘, {
  template:`
    <div>
      <h2>全局组件语法糖</h2>
      <p>全局组件语法糖</p>
    </div>`
})

上面的组件模板都是写在组件里面的,这样写阅读起来不方便,组件模板的分离写法如下:

<!-- 写法一:script标签注意类型是text/x-template -->
<script type="text/x-template" id="cpn1">
  <div>
      <h2>组件模板的分离写法</h2>
      <p>script标签注意类型是text/x-template</p>
    </div>
</script>
<!-- 写法二:template标签 (推荐)--> <template id="cpn2"> <div> <h2>组件模板的分离写法</h2> <p>template标签</p> </div> </template>

JS

const app = new Vue({
  el: "#app",
  components: { //局部组件创建
    cpn1:{
      template:‘#cpn1‘
    },
    cpn2: {
      template: ‘#cpn2‘
    }
  }
})

 

 

组件的动态数据

刚刚创建的组件数据都是静态的,开发中很多数据都是动态数据,我们可以组件中的data解决问题:

<div id="app">
  <cpn1></cpn1>
</div>

const app = new Vue({
  el: "#app",
  components: { //局部组件创建
    cpn1:{
      template:‘<div>{{msg}}</div>‘,
      data(){
        return {
          msg:"组件的数据存放必须要是一个函数"
        }
      }
    }
  }
})

注:组件的data必须是一个函数,而且这个函数返回一个对象保存数据

大家有想过,组件为啥data是一个函数?这里做一个实验,组件cpn1不使用函数,cpn2使用函数:

<div id="app">
  <h2>data不使用函数</h2>
  <cpn1></cpn1>
  <cpn1></cpn1>

  <h2>data使用函数</h2>
  <cpn2></cpn2>
  <cpn2></cpn2>
  <hr>
</div>
<template id="cpn1"> <div> <button @click="count--">-</button> 当前计数:{{count}} <button @click="count++">+</button> </div> </template>
<template id="cpn2"> <div> <button @click="count--">-</button> 当前计数:{{count}} <button @click="count++">+</button> </div> </template>

cpn1返回的公共对象,相当于没有函数的作用域(模拟不使用函数)

const obj = {
  count:0
};
const app = new Vue({
  el: "#app",
  components: { //局部组件创建
    cpn1: {
      template: ‘#cpn1‘,
      data() {
        return obj;//不使用函数
      }
    },
    cpn2: {
      template: ‘#cpn2‘,
      data() {
        return {
          count: 0//使用函数
        }
      }
    }
  }
})

运行结果如下,如果不使用函数它会同加同减,相互作用,这是因为返回的对象地址都是一样的。但使用函数就不会出现这种情况(因为有作用域),它会创建新的地址

技术图片

 

组件是一个封闭的空间,什么意思?即组件的方法不是写着Vue实例里,直接写在组件:

  <div id="app2">
    <mycpn3></mycpn3>
  </div>

  <template id="cpn3">
    <div>
      当前计数:{{count}}
      <button @click="add">+</button>
    </div>
  </template>

JS

   //全局注册组件
    Vue.component(‘mycpn3‘,{
      template:"#cpn3",
      data(){
        return {
          count:0
        }
      },
      methods:{
        add(){
            this.count++;
        }
      }
    });
    //实例Vue
    const app2 = new Vue({
      el:"#app2"
    });

注册组件必须在实例实例Vue前面,不然报错

 

 

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

Vue3.js 全局组价案例入门

Vue3组件化开发

683 vue3的动态组件,keep-alive,缓存组件的生命周期,异步组件和Suspense,$refs,$parent和$root,生命周期,组件的v-model

[vue3进阶] 2.动态组件

如何在vue3中通过点击按钮异步加载组件

35 Vue3异步组件