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的灵 ...
随机推荐
- iOS----------证书的制作
https://developer.umeng.com/docs/66632/detail/66748#createappid Certificates-> 卫生许可证 identifiers ...
- C# Task TaskFactory 异步线程/异步任务
Task是.NetFramework3.0出现的,线程是基于线程池,然后提供了丰富的API TaskFactory 提供对创建和计划 Task 对象的支持 创建和启动异步任务 1.Task task ...
- sudo go 找不到命令
我们使用 sudo 时,使用的配置文件是 /etc/sudoers. 解决配置 /etc/sudoers 文件中的 Defaults secure_path 这一项.将 $GOROOT/bin 目录加 ...
- springcloud vue.js 微服务分布式 前后分离 集成代码生成器 shiro权限 activiti工作流
1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...
- JDK性能分析与故障处理-命令行
一.命令演示登录主机:21docker ps -a | grep 'hub.ecs.com:6999/open_pro.*open-pro-apple2'docker exec -it ID /bin ...
- layui 滚动加载
直接上核心代码,其实官网介绍的很详细: var pageSize = 5;//每次请求新闻的条数 flow.load({ elem: '#newsList' //指定列表容器 ,scrollElem: ...
- ionic项目使用Google FCM插件和Google maps插件打包android报错冲突问题
这段时间在调FCM推送服务的插件 ,原本以为去年调通过,应该很容易,没想到还是出问题了.现将问题及解决方法整理如下,仅供参考: 先看打包报错截图: 详细报错信息:Please fix ...
- maven多仓库配置 公司仓库和阿里仓库
针对公司内网私服仓库,私服仓库不能访问外网,此时无法在私服仓库代理阿里的maven仓库.我们的maven就需要配置多个仓库: maven目录下的conf/settings.xml配置文件: 一.在pr ...
- [Go] golang中的包管理
在配置了环境变量$GOPATH后,比如下面这个路径 export GOPATH=/mnt/f/ubuntu/goProject 在这个路径下面会有这几个目录 在src目录下放着我的源码比如: 在同一个 ...
- Cocos2d-x的坐标系统
推荐转至此处阅读<Cocos2d-x的坐标系统> Cocos2d-x的坐标系统 一.坐标系 二.Cocos2d-x的坐标系统 1.类别 2.定义 三.屏幕坐标系 & OpenGL坐 ...