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的灵 ...
随机推荐
- Nginx配置实例-反向代理实例:根据访问的路径跳转到不同端口的服务中
场景 Ubuntu Server 16.04 LTS上怎样安装下载安装Nginx并启动: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detai ...
- 学习SQL注入---1
开始接触SQL注入了,最开始根据网上的思路做了两道注入的题,但对于SQL注入如何实现,怎么一个流程还是不理解.后来,在网上查找了很多资料,现在一点点去理解. 1.利用sqlmap注入的时候,不是所有页 ...
- Android 再次打开APP进入按Home键退出时的界面(thisTaskRoot)
问题 Android 设置页面的启动模式为 singletask 之后,当按Home 退出时,再重新打开应用,还会进入首启动页.就会造成一些应用需要重新登录,当前页数据丢失等问题 解决 去除启动页的 ...
- RAC修改字符集
字符集修改做过几次了,这次感觉还是有点不顺,走了弯路,再记一遍[概况]准备搭建RAC+RAC DG,发现两端字符集不大一致,担心到时出问题. [目标]将备库NLS_NCHAR_CHARACTERSET ...
- Prometheus学习系列(二)之Prometheus FIRST STEPS
前言 本文来自Prometheus官网手册 和 Prometheus简介 说明 Prometheus是一个监控平台,通过在监控目标上的HTTP端点来收集受监控目标的指标.本指南将向您展示如何使用Pro ...
- C#/.Net开发入门篇(2)——第一个控制台应用程序
相信看了上一篇文章的小伙伴已经安装好自己的开发工具了VS了,这一篇文章就教大家怎么创建第一个应用程序. 下面大家跟着我的操作一起来创建自己的第一个应用程序吧 一.打开VS工具点击左上角的文件→新建→项 ...
- vue element之axios下载文件(后端Python)
axios 接受文件流,需要设置 {responseType:'arraybuffer'} axios.post( apiUrl, formdata, {responseType:'arraybuff ...
- webpack-dev-server config.js Cannot find module
Error: Cannot find module,webpack-dev-server --config 报错找不到模块 webpack-dev-server 设置 webpack.config.j ...
- linux 安装redis服务
下载地址:http://redis.io/download,下载最新稳定版本. 本教程使用的最新文档版本为 2.8.17,下载并安装: $ wget http://download.redis.io/ ...
- [PHP] Workerman中的注册树模式
注册树模式是把对象挂到一个类的属性数组里,下次直接在这个数组里面取,保持全局唯一,一般在项目入口初始化的时候有用到.在workerman中一开始的就是个注册树模式的运用,下面是对他的模拟 <?p ...