阅读 215

vue函数式组件详解

vue函数式组件详解

本篇将详细介绍vue组件化之函数式组件,会用到以下api:

Vue.component()、Vue.extend()、$createElement、patch()。

从事vue开发的小伙伴,平时组件化的过程中大多都采用的vue文件+模块化系统的方式吧。例如:

复制代码

import ComponentA from './ComponentA.vue'export default {
  components: {
    ComponentA
  },  // ...}

复制代码

如果你看过官方文档,了解过vue的组件化,你会发现vue提供创建组件的另一种思路:函数式组件。我身边有从事vue开发的朋友,他们有的对函数式组件并没什么概念,也没有在项目中实际的使用过,下面将和大家一起复习函数式组件的创建和使用。

 官网的函数式组件示例:

复制代码

Vue.component('my-component', {
  functional: true,  // Props 是可选的  props: {    // ...  },  // 为了弥补缺少的实例
  // 提供第二个参数作为上下文
  render: function (createElement, context) {    // ...  }
})

复制代码

将以上示例适当修改,并引入到我们项目中:

child.js

复制代码

import Vue from 'vue';

export default Vue.component('my-component',{ // 该组件抽成js文件,
    functional: true,    // Props 是可选的    props: {      // ...    },    // 为了弥补缺少的实例
    // 提供第二个参数作为上下文
    render: function (createElement, context) {      return createElement('h1', '我是函数式子组件')
    }
  })

复制代码

这里我将该组件抽成单独的js文件,便于复用和维护。在父组件引入该组件:

parent.vue:

复制代码

  
    我是父组件

复制代码

效果:

 

 

 你会发现 <child />和<my-component />都能引入到父组件中,前者好理解,import引入后component中注册,后者为啥能直接用呢?是因为Vue.component()注册的是全局组件

我们再增加一个子组件(跟上面的组件同名):

复制代码

import Vue from 'vue';
//这是函数式组件2
export default Vue.component('my-component',{ // 同名
    functional: true,
    // Props 是可选的
    props: {
      // ...
    },
    // 为了弥补缺少的实例
    // 提供第二个参数作为上下文
    render: function (createElement, context) {
      return createElement('h1', '我是函数式子组件2')
    }
  })

复制代码

现在看看运行效果:

结果会发现,"函数式组件2"被覆盖了!由于Vue.component()同名的组件会覆盖,也因为全局组件不好辨别当前的组件名是否已经注册,所以建议使用Vue.extend()来新建函数式组件。

Vue.extend使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

Vue.extend相当于一个扩展实例构造器,用于创建一个具有初始化选项的Vue子类,在实例化时可以进行扩展选项,最后使用$mount方法绑定在元素上。$mounte会替换被挂载节点下的内容!

Vue.extend和Vue.component之间的关系:

复制代码

<template>
  <div>
    <h1>我是父组件</h1>
    <div id="parent"></div>
    <com />
  </div></template><script>import child from "./child.js";
import Vue from 'vue';
Vue.component('com', child)  

...

复制代码

Vue.extend可以当做Vue.component的组件选项。

 

下面用Vue.extend()创建组件:

child.js:

复制代码

import Vue from 'vue';

export default Vue.extend({,
  // Props 是可选的  props: {
    
  },
  template: `<div>我是extend函数式子组件</div>`  })

复制代码

这里使用的template写法,vue底层执行的时候会将template解析成AST,然后将AST转化为render函数,render的过程vue帮我们处理就好了,所以不习惯写render函数的同学可以用template。

parent.vue:

复制代码

<template>
  <div>
    <h1>我是父组件</h1>
    <div id="parent"></div>
    
  </div></template><script>import child from './child.js'export default {
  name: "parent",
  components: {
    
  },
  data() {    return {
     
    };
  },
  created(){
    
  },
  mounted(){    new child(
      {
        props: {
          val:{            default:6
          }
        },
        methods:{
          func1(){
           console.log("我是方法")
          }
        }
      }
    ).$mount("#parent") // 用$mount()将child产生的实例挂载到id为parent的dom下  },
  methods:{
    
  }
};</script>

复制代码

child.js:

复制代码

import Vue from 'vue';

export default Vue.extend({
  template: `<div>我是extend函数式子组件{{val}}</div>`,
  mounted(){    this.func1()
  }
  
})

复制代码

 

效果:

以上不管是Vue.component()还是Vue.extend()最终都是创建Vue的组件实例,它既不是虚拟dom也不是真实的dom节点。

 

 

 业务中,有些ui库要求我们传入vNode或者真实的dom,例如element UI中的$confirm弹框中的message属性,既可以传普通的字符串,也可以传vNode。下面来手写一段vNode:

复制代码

...
const h = = h('p', 'span', , '内容可以是 ''i', { style: 'color: teal' }, 'VNode'

复制代码

打印:

上面的vNode结构非常简单,h函数的children参数可以手写,但如果vNode结构很复杂的话,手写就显得很凌乱。因此在h函数的第一个参数,我们可以传一个component组件。

复制代码

<template>
  <div>
    <h1>我是父组件</h1>
    <div id="parent"></div>
    
  </div></template><script>import child from './child.js'export default {
  name: "parent",
  components: {
    
  },
  data() {    return {
     
    };
  },
  created(){
    
  },
  mounted(){
    const h = this.$createElement;
    let vNode = h(child,{
      props: {
        val:8,
        func1: ()=>{console.log('哈哈哈哈')}
      }
    })
    console.log(vNode)
  },
  methods:{
    
  }
};</script>

复制代码

 

 

 接下来在elementUI中使用:

复制代码

<template>
  <div>
    <h1>我是父组件</h1>
    <div id="parent"></div>
  </div></template><script>import child from "./child.js";
export default {
  name: "parent",
  components: {},
  data() {    return {};
  },
  created() {},
  mounted() {
    const h = this.$createElement;
    let vNode = h(child, {
      props: {
        val: 8,
        func1: () => {
          console.log("哈哈哈哈");
        },
      },
    });    this.$confirm("提示", {
      title: "提示",
      message: vNode,
      showCancelButton: true,
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }).then(() => {
      
    });
    console.log(vNode);
  },
  methods: {},
};</script>

复制代码

 

 

 

 继续思考,上面ui组件会帮我们将vNode虚拟节点渲染到页面中,如果我想将vNode渲染到我们页面中的某个节点,该怎么实现呢?

其实vue的实例原型上有一个方法:__patch__,而patch函数就是vue中diff算法的核心函数,可以利用它来帮我们完成dom节点的"上树" !

复制代码

<template>
  <div>
    <h1>我是父组件</h1>
    <div id="parent"></div>
  </div></template><script>import child from "./child.js";
export default {
  name: "parent",
  components: {},
  data() {    return {};
  },
  created() {},
  mounted() {
    const h = this.$createElement;
    let vNode = h(child, {
      props: {
        val: 8,
        func1: () => {
          console.log("哈哈哈哈");
        },
      },
    });
    const dom = document.getElementById("parent")    this.__patch__(dom,vNode) //dom是老节点(id为parent),vNode是我们即将渲染的新节点,通过diff算法重新渲染parent节点
  },
  methods: {},
};</script>

复制代码

总结,以上就是我对vue中创建函数式组件的理解,如果还有更佳的实现方式,欢迎留言~

 

来源https://www.cnblogs.com/coder--wang/p/15079261.html

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐