vue jsx与render的区别及基本使用
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的区别及基本使用的更多相关文章
- Vue JSX、自定义 v-model
博客地址:https://ainyi.com/92 最初用到 JSX,就是做这个博客的时候.iview 表格组件,不支持像 element 那样直接写 html 代码渲染,只能通过 render 函 ...
- vue自学入门-6(vue jsx)
目录: vue自学入门-1(Windows下搭建vue环境) vue自学入门-2(vue创建项目) vue自学入门-3(vue第一个例子) vue自学入门-4(vue slot) vue自学入门-5( ...
- element-ui 通用表单封装及VUE JSX应用
一.存在及需要解决的问题 一般在做后台OA的时候会发现表单重复代码比较多,且逻辑基本一样,每次新加一个表单都需要拷贝基本一致的代码结构,然后只是简单地修改对应的字段进行开发 二.预期结果 提取重复的表 ...
- 理解Vue中的Render渲染函数
理解Vue中的Render渲染函数 VUE一般使用template来创建HTML,然后在有的时候,我们需要使用javascript来创建html,这时候我们需要使用render函数.比如如下我想要实现 ...
- vue jsx 使用指南
vue jsx 使用指南 vue jsx 语法与 react jsx 还是有些不一样,在这里记录下. let component = null // if 语句 if (true) { compone ...
- vue和react之间的区别
1.Vue和React之间的区别 相同点: Vue和其他框架一样,都有组件开发和虚拟dom 都支持props进行父子组件之间的数据通信 都支持数据驱动视图,不直接操作真实dom 都支持服务器端的 渲染 ...
- 19 使用Vue实例的render方法渲染组件
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue、React Nactive的区别(转载)
Vue与React的对比 Vue.js与React.js从某些反面来说很相似,通过两个框架的学习,有时候对一些用法会有一点思考,为加深学习的思索,特翻阅了两个文档,从以下各方面进行了对比,加深了对这两 ...
- Vue相关,Vue JSX
JSX简介 JSX是一种Javascript的语法扩展,JSX = Javascript + XML,即在Javascript里面写XML,因为JSX的这个特性,所以他即具备了Javascript的灵 ...
随机推荐
- [JZOJ A组]球 题解
球(ball) [问题描述] 小 T 有 n 个桶和 2n − 1 个球,其中第 i 个桶能装前 2i − 1 个球.每个桶只能装一个球. 现在小 T 取了 m 个桶和 m 个球,并将这些球各自放在 ...
- 通知advice
基于注解的Spring AOP开发,来自https://www.cnblogs.com/junzi2099/p/8274813.html 1.定义目标类接口和实现类 2.编写Spring AOP的as ...
- Xposed的新打开方式--Xpatch工作流程分析
1. Xpatch概述 Xpatch是一款利用重打包的方式,使得被处理的Apk启动时自动加载Xposed模块,来实现应用内Hook的工具. 项目地址:https://github.com/WindyS ...
- 一文带你深入了解JVM性能调优以及对JVM调优的全面总结
目录 JVM调优 概念 基本垃圾回收算法 垃圾回收面临的问题 分代垃圾回收详述1 分代垃圾回收详述2 典型配置举例1 典型配置举例2 新一代的垃圾回收算法 调优方法 反思 一.JVM调优的一些概念 数 ...
- 移动端H5页面开发,碰到一个字体变大的BUG
移动端H5页面开发,碰到一个字体变大的BUG webkit内核下,对不定高宽的元素可能会放大其字体.那么,就可以设置一个max-width:或者使用-webkit-text-size-adjust: ...
- SAP 下钻功能大全
FORM ALV_USER_COMMAND USING R_UCOMM LIKE SY-UCOMM "作为reuse_alv_grid_display的事件i_callback_user_c ...
- ASP.NET Core Web 应用程序系列(五)- 在ASP.NET Core中使用AutoMapper进行实体映射
本章主要简单介绍下在ASP.NET Core中如何使用AutoMapper进行实体映射.在正式进入主题之前我们来看下几个概念: 1.数据库持久化对象PO(Persistent Object):顾名思义 ...
- [css display],table待续
昨天复习了flex布局,今天打算继续,才发现有display:table,今天有的点,别的先写上,其他的后补吧 css display // none 此元素不会被显示. // block 此元素将显 ...
- Android 项目优化(一):项目代码规范优化
项目代码规范为主要包含:类,常量,变量,ID等命名规范:注释规范:分包规范:代码风格规范. 项目代码规范是软件开发过程中非常重要的优化环节. 目前的开发社区提供了很多的开发规范文档,阿里巴巴推出了&l ...
- Navicat Premium 连接oracle 提示ORA-01017:用户名/口令无效;登陆被拒绝
Navicat Premium 连接oracle,密码明明是对的,还是提示 ORA-01017:用户名/口令无效:登陆被拒绝.而用Pl/SQL 连接没有问题. 其实用户名和密码是对的,但还是会报错,这 ...