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. linux系统centos7安装最新版本nginx

    一.准备环境 1.安装centos,一般买一个阿里云测试 2.下载nginx,链接http://nginx.org/download/nginx-1.10.2.tar.gz 二.开始安装 1.cent ...

  2. JUC-6-Callable接口

    创建线程的方式                  不能有返回值,且不能声明抛出异常                                                           ...

  3. mariadb 学习笔记

    安装:yum install mariadb-server mariadb vim /etc/my.cnf.d/server.cnfinnodb_file_per_table = on#设置后当创建数 ...

  4. 你竟然没用 Nuget 构建项目?

    想写这篇文章缘起于公众号文章里的一条留言: 对于一个现代化的开发平台,建立一种让开发者创建,分享与使用可复用代码的机制是十分必要的.这种"可复用代码"被打包后的文件通常被称作&qu ...

  5. 从零开始ant-design-vue-pro开发笔记(一)

    开始 从这里开始是用ant-design-vue组件写ant-design-vue-pro这个后台项目实现步骤的从零开始搭建的过程,视频地址,它采用了ant-desgin-vue的组件库作为素材开发, ...

  6. vue中使用element组件时事件想要传递其他参数的问题

    在使用element的上传组件时在一下几个钩子中传递其他参数 图中是文件上传时的几个钩子,参数为文件或文件列表或者其他参数,但是现在我想在原有参数上传递其他参数.比如我想在on-success的钩子中 ...

  7. Thymeleaf 之 内置对象、定义变量、URL参数及标签自定义属性

    Thymeleaf 之 内置对象.定义变量.URL参数及标签自定义属性 本文章来自[知识林] 如标题所述,这篇文章主要讲述Thymeleaf中的内置对象(list解析.日期格式化.数字格式化等).定义 ...

  8. 基于C# 百度AI和科大汛飞语音合成SDK

    一.百度语音合成 百度语音合成C# SDK主要是基于Rest API,需要互联网调用HTTP接口,Rest API 仅支持最多512个汉字,合成的格式文件为MP3,没有其它的格式.如果想离线使用需下载 ...

  9. C#后台架构师成长之路-进阶体系篇章大纲

    这些知识体系概念和应用如果不了解,怎么修炼你的内功..... 1.数据类型的理解,比如bool,byte,short,ushort,int,uint,long,ulong,float,double,s ...

  10. python判断字典中key是否存在

    例:#生成一个字典d = {'title':'abc','age':18} if 'title' in d.keys(): print('存在')else: print('不存在') if 'titl ...