vue template语法简单明了,数据操作与视图分离,开发体验友好。但是在某些特定场合中,会限制一些功能的扩展,如动态使用过滤器解析字符串类型的模板文件等。以上功能的实现可以借助vue的render语法,render语法比template更偏底层,允许在HTML中使用js语法,可以极大的扩展HTML的能力。

  render函数注入了一个参数createElement,用来创建我们所需要的标签内容,有三个参数:HTML标签(elementTag)标签属性(option)子元素(children);从createElement的参数列表里面可以看出,如果组件内部结构嵌套比较深,render的语法写起来会比较繁琐,需要不断的调用createElement,对于想偷懒的我,还是想想有没有什么比较简易的写法,jsx无疑是一种很好的选择,区别在于jsx可以像我们写HTML文件一样写业务代码,借助于babel,会将jsx语法转换成render语法,没有什么副作用。

  最近在使用ant-design-vue进行项目重构,现就以ant-desigin-vue为例,介绍下vue jsx的基本使用。

  1、安装vue jsx开发环境

    已vue-cli 3.0脚手架为例,首先需要安装babel转义插件,将vue jsx转义成vue的render语法,执行以下命令:

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props -D

    其次,修改babel配置文件(babel.config.js/.babelrc),如下:

module.exports = {
presets: [
['@vue/app', {
useBuiltIns: 'entry'
}],
['@vue/babel-preset-jsx',
{
"injectH": false
}]
]
};

  注意@vue/babel-preset-jsx默认会注入一个h(createElement的语法糖),会与vue render函数注入的createElement冲突,这个配置要设置false,否则项目启动会报错

  2、基本使用

    jsx并不能解析vue指令,因此template转jsx语法时,每一部分的对应写法和vue官网文档一致,如下:

{
// 与 `v-bind:class` 的 API 相同,
// 接受一个字符串、对象或字符串和对象组成的数组
'class': {
foo: true,
bar: false
},
// 与 `v-bind:style` 的 API 相同,
// 接受一个字符串、对象,或对象组成的数组
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML 特性
attrs: {
id: 'foo'
},
// 组件 prop
props: {
myProp: 'bar'
},
// DOM 属性
domProps: {
innerHTML: 'baz'
},
// 事件监听器在 `on` 属性内,
// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
// 需要在处理函数中手动检查 keyCode。
on: {
click: this.clickHandler
},
// 仅用于组件,用于监听原生事件,而不是组件内部使用
// `vm.$emit` 触发的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
// 赋值,因为 Vue 已经自动为你进行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽的格式为
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果组件是其它组件的子组件,需为插槽指定名称
slot: 'name-of-slot',
// 其它特殊顶层属性
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
// 那么 `$refs.myRef` 会变成一个数组。
refInFor: true
}

  具名插槽:{ this.$slots.slotName }

  v-for转换:

const formItems = this.formFields.map(vv => {
const itemProps = {
props: {
label: vv.label
}
};
if (Object.is(vv.type, 'input')) {
const inputProps = {
domProps: {
autocomplete: 'off'
},
directives: [{
name: 'decorator',
rawName: 'v-decorator',
value: [vv.prop, {rules: vv.rules}]
}]
};
return <a-form-item {...itemProps}>
<a-input {...inputProps} />
</a-form-item>
}
});

  附一个基于ant-design-vue form封装的弹窗表格组件:

/**
* 简单的通用表单弹框
* 配置文件以vue jsx为准
*/
//中间量,用于CustomizedForm与keCommonForm之间数据的传输
const CustomizedForm = {
props: {
formFields: {
type: Array,
default() {
return [];
}
},
layout: {
type: String,
default: 'inline'
}
},
created () {
let _this = this;
this.form = this.$form.createForm(this, {
onFieldsChange: (props, changedFields) => {
_this.$emit('fieldsChange', changedFields);
},
mapPropsToFields: () => {
let formFieldsBean = {};
_this.formFields.forEach(vv => {
formFieldsBean[vv.prop] = _this.$form.createFormField({
value: vv.value
});
});
return formFieldsBean;
},
onValuesChange (props, value, currentValue) {
_this.$emit('change', currentValue);
}
});
//传递form对象
this.$emit('childScope', this.form);
},
render() {
let _this = this; const formProps = {
props: {
layout: this.layout,
form: this.form
},
attrs: {
class: 'ke-form ke-form-inline'
}
}; const formItems = this.formFields.map(vv => {
const itemProps = {
props: {
label: vv.label
}
};
//深拷贝一份表单属性,防止报错
const inputProps = {
attrs: {
autocomplete: 'off'
},
scopedSlots: {},
directives: [{
name: 'decorator',
rawName: 'v-decorator',
value: [vv.prop, {rules: vv.rules}]
}]
};
//如果有配置表单信息,合并表单属性
if (_.isObject(vv.options)) {
Object.assign(inputProps, vv.options);
}
//如果存在插槽,则配置插槽信息
if (_.isObject(vv.scopedSlots)) {
Object.keys(vv.scopedSlots).forEach(key => {
let formItemOptions = _.cloneDeep(vv.scopedSlots[key].options);
inputProps.scopedSlots[key] =
() => _this.$createElement(vv.scopedSlots[key].tagName, formItemOptions);
})
}
//获取创建元素的tagName
let tagName = vv.tagName || 'a-input';
let item = this.$createElement(tagName, inputProps);
return <a-form-item {...itemProps}>
{ item }
</a-form-item>
}); return (
<a-form {...formProps}>
{ formItems }
</a-form>
);
}
}; /**
* 简单的表单可以引用此组件
*/
export default {
name: 'keCommonForm',
model: {
prop: 'value',
event: 'change'
},
props: {
title: {
type: String,
default: '提示'
},
visible: {
type: Boolean,
default: false
},
okText: {
type: String,
default: ''
},
layout: {//表格的排列方式 'horizontal'|'vertical'|'inline'
type: String,
default: 'inline'
},
formFields: {//表格的配置文件Array<Object>
type: Array,
default() {
return []
}
},
value: {
type: Object,
default() {
return {}
}
},
submitFun: {//提交表单触发父组件内部的方法
type: String,
default: 'test'
},
closeResetFields: {//关闭模态框重置表单内容
type: Boolean,
default: true
},
commonFormOption: {
type: Object,
default() {
return {}
}
}
},
components: { CustomizedForm },
methods: {
onCancel() {
this.$emit('closeCommonForm')
},
onOk() {
let checkedList = this.formFields.map(vv => vv.prop);
if (this._form && _.isFunction(this._form.validateFieldsAndScroll)) {
this._form.validateFieldsAndScroll(checkedList, (errors, value) => {
if (errors && _.isObject(errors) && Object.keys(errors).length > 0) {
// Object.keys(errors).forEach(vv => {
// this.$message.error(errors[vv].errors[0].message, 2);
// })
return;
}else {
this.$emit('submit', this.submitFun);
}
})
} },
formChange(value) {
this.$emit('change', value);
}
},
render() {
//模态框关闭后的回调
let _this = this;
function afterClose() {
if (_this.closeResetFields) {
_this._form.resetFields();
}
} const confirmBtnProps = {
props: {
type: 'primary',
'html-type': 'submit'
},
on: {
click: this.onOk
}
}; const modalProps = {
props: {
title: this.title,
okText: this.okText,
visible: this.visible,
afterClose: afterClose
},
on: {
cancel: this.onCancel,
on: this.onOk
},
scopedSlots: {
footer: scope => {
return <div>
<a-button { ...confirmBtnProps }>提交</a-button>
<a-button onClick={ this.onCancel }>取消</a-button>
</div>
}
}
};
//合并通用表单配置文件,支持jsx语法
if (_.isObject(this.commonFormOption)) {
Object.assign(modalProps, this.commonFormOption);
} const customizedFormProps = {
props: {
formFields: this.formFields,
layout: this.layout
},
on: {
change: this.formChange,
childScope: form => {
this._form = form;
}
}
};
return (
<a-modal {...modalProps}>
{ this.$slots.content }
<CustomizedForm { ...customizedFormProps } />
</a-modal>
)
}
}

vue jsx与render的区别及基本使用的更多相关文章

  1. Vue JSX、自定义 v-model

    ​博客地址:https://ainyi.com/92 最初用到 JSX,就是做这个博客的时候.iview 表格组件,不支持像 element 那样直接写 html 代码渲染,只能通过 render 函 ...

  2. vue自学入门-6(vue jsx)

    目录: vue自学入门-1(Windows下搭建vue环境) vue自学入门-2(vue创建项目) vue自学入门-3(vue第一个例子) vue自学入门-4(vue slot) vue自学入门-5( ...

  3. element-ui 通用表单封装及VUE JSX应用

    一.存在及需要解决的问题 一般在做后台OA的时候会发现表单重复代码比较多,且逻辑基本一样,每次新加一个表单都需要拷贝基本一致的代码结构,然后只是简单地修改对应的字段进行开发 二.预期结果 提取重复的表 ...

  4. 理解Vue中的Render渲染函数

    理解Vue中的Render渲染函数 VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数.比如如下我想要实现 ...

  5. vue jsx 使用指南

    vue jsx 使用指南 vue jsx 语法与 react jsx 还是有些不一样,在这里记录下. let component = null // if 语句 if (true) { compone ...

  6. vue和react之间的区别

    1.Vue和React之间的区别 相同点: Vue和其他框架一样,都有组件开发和虚拟dom 都支持props进行父子组件之间的数据通信 都支持数据驱动视图,不直接操作真实dom 都支持服务器端的 渲染 ...

  7. 19 使用Vue实例的render方法渲染组件

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. vue、React Nactive的区别(转载)

    Vue与React的对比 Vue.js与React.js从某些反面来说很相似,通过两个框架的学习,有时候对一些用法会有一点思考,为加深学习的思索,特翻阅了两个文档,从以下各方面进行了对比,加深了对这两 ...

  9. Vue相关,Vue JSX

    JSX简介 JSX是一种Javascript的语法扩展,JSX = Javascript + XML,即在Javascript里面写XML,因为JSX的这个特性,所以他即具备了Javascript的灵 ...

随机推荐

  1. SpringCloud-创建服务消费者-Ribbon方式(附代码下载)

    场景 SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  2. gdisk转fdisk

    分区测试的时候发现之前用gdisk分区之后,就无法用fdisk进行分区了,哪怕格式化了也不行,通过fdisk 查看硬盘,发现硬盘都变成了GPT分区,无法通过fdisk进行分区操作,所以要通过parte ...

  3. JavaScript实例:运动的小球

    本篇博文通过制作一个小球运动动画的实例,来学习在HTML5的画布上实现动画制作的方法,同时理解面向对象程序设计的基本思想. 1.绘制小球 先在HTML页面中设置一个画布. <canvas id= ...

  4. 记druid 在配置中心下的一个大坑: cpu 达到 100%

    把我们的dubbo 应用移步到配置中心上去之后,发现我们的应用过一段时间就会出现cpu 100%的情况 (大概是12个小时),一开始cpu占用是2-5% 的样子,什么都没做,后面竟然用尽了cpu.. ...

  5. Ansible-playbook之定义变量

    1.引用变量 # 变量引用方式 "{{ }}" 2.定义变量 (vars) - hosts: web # 定义变量 vars: - play_var: This_is_play_v ...

  6. jquery 点击tr选中checkbox,解决checkbox的默认点击事件被阻止的问题

        1.第一种,!$(event.target).is('input'),判断触发事件的元素是否为input.此时使用event.target,而不是this,获取事件本身,防止触发事件冒泡的问题 ...

  7. Unicode、UTF-8、Big Endian、Little Endian、GBK、UCS-2

    一.Unicode.UCS.GBK 1.开始计算机只在美国用.八位的字节一共可以组合出256(2的8次方)种不同的状态.把这些0×20以下的字节状态称为”控制码”.他们又把所有的空 格.标点符号.数字 ...

  8. Spring基础——AOP通知

    spring(AOP通知) 切面 切面是封装通用业务逻辑的组件,可以作用到其他组件上.是spring组件中的某个方法.无返回类型.参数类型与通知类型有关.一个切面 开启数据库 关闭数据库 开启事务 检 ...

  9. angular cli + primeNG

    目录: 1.安装  angular cli 2.创建项目 3.构建路由 4.新建组件 5.组件之间的通信 6.引入primeNG 7.修改primeNG组件样式 8.问题 -------------- ...

  10. C lang:Array_Multidimensional arrays

    #include<stdio.h> #include<windows.h> #define YEARS 5 #define MONTHS 12 void color(short ...