• Vue中 render 函数应用


    前言

    因为最近接手维护一个基于 ivew 的项目, 新增模块中包含很多自定义功能, 所以大量使用到了 render 函数; 故对其做一下总结...关于 render 函数, 官方文档也做了比较详细的介绍: render 函数: https://cn.vuejs.org/v2/guide... ; 一般组件我们都是用 template模板的方式去写; 有时候会造成代码上的冗余, 不好扩展.

    了解 render 函数

    在学习 render 函数之前, 最好先了解一下虚拟节点 vNode, 以及虚拟节点树组成的虚拟vDom, 这样会更好的理解 render 函数

    /*
     *@describe {渲染函数}
     *@params {见下方} 
     *@returns {一段VNode}
     */
    createElement函数: 通常写为 h 函数, 也是官方推荐的
    
    h(
      // {String | Object | Function} => 'p' | 'Select' | (h, p) => {}
      // 一个 html 标签名、组件选项对象,或者
      // resolve 了上述任何一种的一个 async 函数。必填项。
      'div',
    
      // {Object}
      // 一个与模板中属性对应的数据对象。可选。
      {
         style: {
              '100px'
         },
      },
    
      // {String | Array}
      // 子级虚拟节点 (VNodes),一般是数组: 由 `h()` 构建而成,参数: ('标签|组件', {attrs}, text)
      // 也可以使用字符串来生成“文本虚拟节点”。可选。
      [
        '先写一些文字',
       h('h1', '一则头条'),
       h(MyComponent, {
          props: {
            someProp: 'foobar'
          }
        })
      ]
    )

    render 函数应用1: 函数式组件

    函数式组件 可以看做是组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的html字符串
    对于函数式组件,可以这样定义:

    Stateless(无状态):组件自身是没有状态的
    Instanceless(无实例):组件自身没有实例,也就是没有this  
    由于函数式组件中没有this,参数需要靠context来传递;
    export default {
      name: 'functional-button',
      functional: true,
      render (h, context) {
        return h('button', '按钮 1 号')
      }
    }

    由官方文档可知: context 参数如下:

    props:提供所有 prop 的对象
    children: VNode 子节点的数组
    slots: 一个函数,返回了包含所有插槽的对象
    scopedSlots: (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。
    data:传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件
    parent:对父组件的引用
    listeners: (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是data.on 的一个别名。
    injections: (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性。

    使用函数式组件

    <template>
      <div class="home">
        <func-button>
          hello button
        </func-button>
      </div>
    </template>
    
    <script>
    import FuncButton from '../function-components/func-button'
    export default {
      name: 'home',
      components: {
        FuncButton
      }
    }
    </script>

    现在我们将这个 func-button.js 组件改造一下, 上面的hello button 文本节点为func-button.js的childern属性(数组|String),我们可以让父组件去控制组件的button按钮内容, 改写如下:

    // export default {
    //   name: 'functional-button',
    //   functional: true,
    //   render (h, context) {
    //     return h('button', '按钮 1 号')
    //   }
    // }
    export default {
      name: 'funtional-button',
      functional: true,
      render (h, { children }) {
        return h('button', children)
      }
    }

    如何添加事件呢?

    code如下:

    <template>
      <div class="home">
        <func-button @click="handleClick">
          hello button
        </func-button>
      </div>
    </template>
    
    <script>
    import FuncButton from '../function-components/func-button'
    export default {
      name: 'home',
      components: {
        FuncButton
      },
      methods: {
        handleClick () {
          alert('你点到我了')
        }
      }
    }
    </script>
    // func-button组件
    export default {
      functional: true,
      // 组件的属性集成在data里, 为了简便,我们可以用 data 来替换下面的 props, listeners等
      // 写成 h('button', data, ['hello', ...children])
      render (h, { props, listeners, children }) {
        return h(
          'button',
          {
            attrs: props,
            on: {
              click: listeners.click
            }
          },
          children
        )
      }
    }

    render 函数应用2: JSX 语法

    平时开发还是多用temlate因为直观简洁,各种指令用着很方便,但是经常写template有时会觉得代码看着很冗余,如果想自己控制渲染逻辑比如循,判断等等时我们就可以考虑使用JSX

    <script>
    export default {
      name: 'h-title',
      props: {
        id: {
          type: Number,
          default: 1
        }
      },
      render () {
        const hText = `<h${this.id}>${this.$slots.default[0].text}</h${this.id}>`
        return <div domPropsInnerHTML={hText}></div>
      }
    }
    </script>

    资源搜索网站大全 https://www.renrenfan.com.cn 广州VI设计公司https://www.houdianzi.com

    render 函数应用 3: 定制化组件

    // List.vue 组件
    <template>
        <div>
            <template v-for="(item, index) in data">
                <li :key="index" v-if="!render">{{ item }}</li>
                <ListItem
                    v-else
                    :key="`a${index}`"
                    :render="render"
                    :item="item"
                ></ListItem>
            </template>
        </div>
    </template>
    
    <script>
    import ListItem from "./list-item"
    
    export default {
        components: {
            ListItem
        },
        props: {
        // 支持自定义渲染
            render: {
                type: Function
            },
            data: {
                type: Array,
                default: () => []
            }
        }
    };
    </script>
    
    // list-item.js
    export default {
        props: {
            render: {
                type: Function
            },
            item: {
                type: String
            }
    
        },
        render(h) { // createElement  
            return this.render(h, this.item)
        }
    }
    // 父组件中
    <List :data="['香蕉','苹果','橘子']" :render="render"></List>
    // 可以渲染你想要的标签和内容
    render (h, data) { 
          return <span>{data}</span>
    }
  • 相关阅读:
    Fast Member
    C++箴言:理解typename的两个含义
    网上资源工具
    WeakReference
    MonoGame教程
    The RAII Programming Idiom
    OpenGL Common Mistakes
    Finalize()、Dispose()、SafeHandle、GC
    Interop with Native Libraries
    C++计算几何库
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/14092478.html
Copyright © 2020-2023  润新知