动态组件 VS 异步组件

1. 动态组件

  • 动态组件就是 component组件 , 组件身上可以绑定一个is属性, 用来表示某一个组件。

  • 通过使用保留的  元素,动态地绑定到它的 is 特性,我们让多个组件可以使用同一个挂载点,并动态切换。根据 v-bind:is=“组件名” 中的组件名去自动匹配组件,如果匹配不到则不显示。

2. is属性(改变挂载的组件,只需要修改is指令的值即可。)

  • 我们html中有一些标签是规定它的直接子元素的 , 比如 ul li ol li selector option table这类型标签
  • 不能直接用常规的组件使用方式, 必须在对应直接子元素上绑定 is属性
<div id="app">
<table>
<tr>
<td>aa</td>
<td>bb</td>
<td>cc</td>
</tr>
<!-- is = 组件名称 -->
<tr is = 'my-table'></tr>
</table>
</div>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 动态组件</title>
<script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
    <button @click='toShow'>点击显示子组件</button>
    <component v-bind:is="which_to_show"></component>
</div>
<script>
// 创建根实例
new Vue({
el: '#app',
data:{
     which_to_show:'first'
},
    methods:{
        toShow:function(){
            var arr = ["first","second","third"];
            var index = arr.indexOf(this.which_to_show);
            if(index<2){
                this.which_to_show = arr[index+1];
            }else{
                this.which_to_show = arr[0];
            }
        }
    },
    components:{
        first:{
            template:'<div>这是子组件1<div>'
        },
        second:{
            template:'<div>这是子组件2<div>'
        },
        third:{
            template:'<div>这是子组件3<div>'
        },
    }
})
</script>
</body>
</html>

3. keep-alive组件

  • 将组件的内容存在浏览器缓存中, 当我们需要重复渲染的时候, 就从浏览器缓存中去调用,这样可以减少性能消耗

  • 动态切换掉的组件(非当前显示的组件)是被移除掉了,如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令参数:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 动态组件</title>
<script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
    <button @click='toShow'>点击显示子组件</button>
    <!----或者<component v-bind:is="which_to_show" keep-alive></component>也行----->
    <keep-alive>
    <component v-bind:is="which_to_show" ></component>
    </keep-alive>
</div>
<script>
// 创建根实例
new Vue({
el: '#app',
data:{
     which_to_show:'first'
},
    methods:{
        toShow:function(){
            var arr = ["first","second","third"];
            var index = arr.indexOf(this.which_to_show);
            if(index<2){
                this.which_to_show = arr[index+1];
            }else{
                this.which_to_show = arr[0];
            }  console.log(this.$children); 
        }
    },
    components:{
        first:{
            template:'<div>这是子组件1<div>'
        },
        second:{
            template:'<div>这是子组件2<div>'
        },
        third:{
            template:'<div>这是子组件3<div>'
        },
    }
})
</script>
</body>
</html>
<keep-alive>
<component is = "A"></component>
</keep-alive>
说明:
  • 初始情况下,vm.$children属性中只有一个元素(first组件),
  • 点击按钮切换后,vm.$children属性中有两个元素,
  • 再次切换后,则有三个元素(三个子组件都保留在内存中)。
  • 之后无论如何切换,将一直保持有三个元素。

4. 不常用指令

  • v-text vs v-html
  • 都是用来将数据插入DOM中, 但是v-html可以解析标签类型数据
  • v-cloak 解决 {{}} 语法短暂原样输出
  • v-pre 原样输出
  • v-once 只渲染一次

- 代码示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
  <style>
    [v-cloak]{
      display: none;
      /* visibility: hidden; */
      /* opacity: 0; */
    }
  </style>
</head>
<body>
  <div id="app">
    <h3> v-text </h3>
    <p> {{ msg }} </p>
    <p v-text = "msg"></p>
    <div v-text = "title"></div>
    <h3> v-html </h3>
    <div v-html = "title"></div>
    <div v-html = "msg"></div>
    <h3> v-pre </h3>
    <p v-pre>
      {{ msg }}
    </p>
    <h3> v-cloak </h3>
    <p v-cloak>
      {{ msg }}
    </p>
    <h3> v-once </h3>
    <p v-once>
      {{ msg }}
    </p>
  </div>
</body>
<script>
  new Vue({
    el: '#app',
    data: {
      msg: 'hello vue.js',
      title: '<h3> hello title </h3>'
    }
  })
</script>
</html>

5. 异步组件

在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 向 `resolve` 回调传递组件定义
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:


Vue.component('async-webpack-example', function (resolve) {
  // 这个特殊的 `require` 语法将会告诉 webpack
  // 自动将你的构建代码切割成多个包,这些包
  // 会通过 Ajax 请求加载
  require(['./my-async-component'], resolve)
})
  • 异步组件也是一个函数, 只不过这个函数使用Promise,函数有一个返回值

代码示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="../../basic-source/vue.js"></script>
</head>
<body>
  <div id="app">
    <async-com></async-com>
  </div>
</body>
<script>
  var result = new Promise(function( resolve, reject ){
    resolve({
      template: '<div> 异步组件 </div>'
    })
  })
  Vue.component('AsyncCom',async () => {
    const tpl = await result.then( res => res)
    return tpl
  })
  // Vue.component('async-com', function (resolve, reject) {
  // setTimeout(function () {
  // // 向 `resolve` 回调传递组件定义
  // resolve({
  // template: '<div>I am async!</div>'
  // })
  // }, 1000)
  // })
  new Vue({
    el: '#app'
  })
</script>
</html>

接下来,我们可以封装一个异步组件,
代码如下:

/*
  js文件
*/
const asyncCom = {
  createAsyncCom({
    selector,
    asyncComName,
    methods,
    data,
    watch,
    computed,
    filters,
    directives,
    components,
    delay}){
    var result = new Promise(function( resolve, reject ){
      resolve({
        template: selector,
        methods,
        data,
        watch,
        computed,
        filters,
        directives,
        components
      })
    })
    setTimeout(()=>{
      Vue.component(asyncComName,async () => {
        const tpl = await result.then( res => res)
        return tpl
      })
    },delay)
  }
}
export default {
  createAsyncCom: asyncCom.createAsyncCom
}

. 高阶组件(HOC) higt order component

高阶组件(HOC)是 React 生态系统的常用词汇,React 中代码复用的主要方式就是使用高阶组件,并且这也是官方推荐的做法。而 Vue 中复用代码的主要方式是使用 mixins,并且在 Vue 中很少提到高阶组件的概念,这是因为在 Vue 中实现高阶组件并不像 React 中那样简单,原因在于 React 和 Vue 的设计思想不同,但并不是说在 Vue 中就不能使用高阶组件,只不过在 Vue 中使用高阶组件所带来的收益相对于 mixins 并没有质的变化。本篇文章主要从技术性的角度阐述 Vue 高阶组件的实现,且会从 React 与 Vue 两者的角度进行分析。

高阶组件是一个函数, 这个函数的作用是进行组件的复用

所谓高阶组件其实就是高阶函数啦,React 和 Vue 都证明了一件事儿:一个函数就是一个组件。所以组件是函数这个命题成立了,那高阶组件很自然的就是高阶函数,即一个返回函数的函数,我们知道在 React 中写高阶组件就是在写高阶函数,很简单,那是不是在 Vue 中实现高阶组件也同样简单呢?其实 Vue 稍微复杂,甚至需要你对 Vue 足够了解,接下来就让我们一块在 Vue 中实现高阶组件,在文章的后面会分析为什么同样都是 函数就是组件 的思想,Vue 却不能像 React 那样轻松的实现高阶组件。

了解了这些,接下来我们就可以开始着手实现 Vue 高阶组件了,为了让大家有一个直观的感受,我仍然会使用 React 与 Vue 进行对比的讲解。首先是一个基本的 Vue 组件,我们常称其为被包装组件(WrappedComponent),假设我们的组件叫做 BaseComponent:

base-component.vue
<template>
    <div>
     <span @click="handleClick">props: {{test}}</span>
    </div>
</template>
<script>
export default {
    name: 'BaseComponent',
    props: {
     test: Number
    },
    methods: {
     handleClick () {
        this.$emit('customize-click')
     }
    }
}
</script>

我们观察一个 Vue 组件主要观察三点:props、event 以及 slots。对于 BaseComponent 组件而言,它接收一个数字类型的 props 即 test,并发射一个自定义事件,事件的名称是:customize-click,没有 slots。我们会这样使用该组件:

<base-component @customize-click="handleCustClick" :test="100" />

代码示例

class HOC {
  //复用性代码
  sum(){
    //一万行代码
    return 1+1
  }
  init(Com){
    return <Com sum = { this.sum }/>
  }
}
export default {
  init: HOC.init
}
const A = init(A)
const B = init(B)

猜你喜欢

转载自blog.csdn.net/xuwei1215225/article/details/89497950