vue2渲染函数render

1,168 阅读2分钟

image.png

相信使用vue的同学,render渲染函数都是听过的,但是用的不多,毕竟模板语法完全够用,且模板语法更加的直观

但是有些时候使用render函数很香的,这个官网给了一个很好的例子

image.png

代码复用

render毕竟是纯js,既然是js那么就是有js的全部功能和特性(MC没有bug只有特性)

这个最好的体现在我自己二次封装组件了,在写公共props的时候我可以写一个公共的props然后和外部传入进来的props进行合并,减少重复工作

render(createElement: CreateElement, vm: DynamicForm, formItem: FormItemConfig) {
  const config = RenderUtils.getConfig(vm, formItem, {
    props: {
      disabled: RenderUtils.setDisabled(formItem, vm) // 增强disabled
    },
    attrs: {
      placeholder: formItem.props?.placeholder || '请输入' + formItem.label,
    },
  }, this)
  const children = RenderUtils.renderSlotsChildren(formItem, createElement, this.slotNames, vm)
  return [
    createElement(`el-input`, config, children)
  ]
},
static getConfig(
  vm: DynamicForm,
  formItem: FormItemConfig,
  config: VNodeData,
  renderType: RenderTypeItem
): VNodeData {
  return {
    ref: RenderUtils.formItemToRef(formItem),
    refInFor: true,
    // @ts-ignore
    model: RenderUtils.getModelConfig(vm, formItem),
    props: {
      ...formItem.props,
      ...config.props
    },
    directives: [
      RenderUtils.getTitle(vm, formItem, renderType.getTitle),
      ...(config.directives || [])
    ],
    attrs: {
      ...formItem.props,
      ...config.attrs,
      title: undefined,
    },
    on: {
      ...formItem.events,
      'hook:created': () => {
        formItem.events?.['hook:created'] && formItem.events['hook:created']()
      },
      ...config.on
    },
    nativeOn: {
      ...formItem.events,
      ...config.nativeOn
    }
  }
}

减少组件层级

当你二次封装el-table的时候,多级表头如果你使用模板语法那就要多创建一个vue文件去做递归,递归组件

image.png

image.png

使用render函数你就可以直接包装成一个函数,使用函数去递归,这样你的组件层级不会多一个,但是就是可阅读性极差

image.png

v-model的另一种实现

在官网中,v-model在render函数中实现是要自己去实现

image.png

但是偶然的一次在看文件编译的时候发现还有一种方式,官网没有讲,这也打消了我对jsx实现v-model的乱想(我没有去babel-jsx的源码 ̄□ ̄||)O(∩_∩)O

在源码编译中,编译出来的render函数里面会有一个model的选项,这是我已经写好的

image.png

我们看一下编译的,

源代码

<template>
  <div>
    <el-input v-model="value"></el-input>
  </div>
</template>

<script>
export default {
  name: 'EmptyHome',
  data(){
    return {
      value: ''
    }
  }
}
</script>

<style scoped lang="scss">

</style>

编译出来的

const __vue2_script = {
  name: 'EmptyHome',

  data() {
    return {
      value: ''
    };
  }

};
import { render as __vue2_render, staticRenderFns as __vue2_staticRenderFns } from "D:/CODE/nodejs/project/vue2-learning/src/EmptyHome.vue?vue&type=template&lang.js";
const __cssModules = {};
/* normalize component */

import __vue2_normalizer from "/vite/vueComponentNormalizer";

var __component__ = /*#__PURE__*/__vue2_normalizer(__vue2_script, __vue2_render, __vue2_staticRenderFns, false, __vue2_injectStyles, null, null, null);

function __vue2_injectStyles(context) {
  for (let o in __cssModules) {
    this[o] = __cssModules[o];
  }
}

__component__.options.__file = "src/EmptyHome.vue";
/* hot reload */

import __VUE_HMR_RUNTIME__ from "\u0000/vite/vueHotReload";
import __VUE_IDENTIFIER__ from "vue";

__VUE_HMR_RUNTIME__.install(__VUE_IDENTIFIER__);

if (!import.meta.env.SSR && __VUE_HMR_RUNTIME__.compatible) {
  if (!__VUE_HMR_RUNTIME__.isRecorded("b35343ba")) {
    __VUE_HMR_RUNTIME__.createRecord("b35343ba", __component__.options);
  }

  import.meta.hot.accept(update => {
    __VUE_HMR_RUNTIME__.reload("b35343ba", update.default);
  });
  import.meta.hot.accept("/src/EmptyHome.vue?vue&type=template&lang.js", update => {

  var _h = _vm.$createElement;

  var _c = _vm._self._c || _h;

  return _c('div', [_c('el-input', {
    model: {
      value: _vm.value,
      callback: function callback($$v) {
        _vm.value = $$v;
      },
      expression: "value"
    }
  })], 1);
};

var staticRenderFns = [];
render._withStripped = true;
export { render, staticRenderFns };

image.png

这个在createElement没有定义,官网也没有说,但是确实是可以用的,这样用render写v-model就会变得简单

如果不是model,而是sync这个vue是有约定的,所以编译出来的也很好理解

image.png

image.png

最后

这篇文章主要想讲的就是render函数v-model的另一种官网没有写的写法O(∩_∩)O,也是在这里记录一下