最进在写一个vue项目,刚开始考虑是不是用jsx和vue结合来搞,减少代码量,项目中一些公用的组件,用jsx语法重新包裹,这样方便很多,而且使用jsx语法更加的灵活,然后把公用组件注入到根组件里去,每个页面可以直接引用,这样,组件的功能性和扩展性就很强,感觉是一种很爽的vue开发方式,然后就这样做了,以下就介绍一下基本流程。
之前,推荐阅读一篇介绍,首先 vue 中默认是不支持 JSX 的,我们需要在项目中安装一些 npm 包 babel-plugin-transform-vue-jsx,babel-plugin-jsx-v-model
https://github.com/vuejs/jsx#installationgithub.com然后在 .babelrc 文件中加入,如果没有这个文件,需要在项目的根路径创建这个文件
![7211da220bbc553e0691e6c05921a435.png](https://img-blog.csdnimg.cn/img_convert/7211da220bbc553e0691e6c05921a435.png)
我们可以定义一个comp的文件,用来存放公共组件,然后进行组件注入全局。截图如下。
![9da2b9f171b5f02ec32867d713dd3539.png](https://img-blog.csdnimg.cn/img_convert/9da2b9f171b5f02ec32867d713dd3539.png)
这样页面可以直接使用这些组件,不需要每个页面都引入一遍啦。
那么,在vue中组件里面怎么用jsx实现呢?
这就需要我们对vue是怎么渲染函数和组件的,推荐阅读官方文章:
渲染函数 & JSX — Vue.jscn.vuejs.org![80cfdc3c3481b901ce58bd00c3100455.png](https://img-blog.csdnimg.cn/img_convert/80cfdc3c3481b901ce58bd00c3100455.png)
文章上需要注意的一点是:
![601d89a689d06df31dd8f26858764cb4.png](https://img-blog.csdnimg.cn/img_convert/601d89a689d06df31dd8f26858764cb4.png)
然后,我们试着写一个很简单的jsx的组件:比如,我们重新包裹一个树组件:
import Vue from 'vue'
import Component from 'vue-class-component'
import { Tree } from 'ant-design-vue'
@Component({})
export default class PMTree extends Vue {
getJSX () {
let config = {
props: {
treeData: this.$attrs.treeData
}
}
return this.$createElement(Tree, config)
}
render () {
return this.getJSX()
}
}
注意这里的this.$createElement,其实vue对组件的识别就是一个这个函数的调用。
如果你需要监听一些函数,或者传一些属性进来,比如这个jsx组件:我们对select重新包裹,这样更方便统一调样式或者处理逻辑:
import Vue from 'vue'
import Component from 'vue-class-component'
import { Select } from 'ant-design-vue'
@Component({
props: {
belong: String,
selectOptions: Array,
size: String,
placeholder: String,
}
})
export default class PMButton extends Vue {
getJSX () {
let { $attrs, $props, $listeners } = this
let { change } = $listeners
let { selectOptions, placeholder, belong } = $props
return (
// 这里这样写是为了change的时候拿到dom元素处理逻辑,也可以写成on-change={change}
<Select on-change={(e,$event)=>change(e,$event)} {...{props}} placeholder={placeholder} style={{width: '100px'}}>
{
selectOptions.map((item,index) =>
<Select.Option key={index} value={item.id || item } >
{item.name}
</Select.Option>
)
}
</Select>
)
}
render () {
return this.getJSX()
}
}
我们既可以传进来$props,$attrs,$listeners。。。因为是继承Vue实例,所以,这些值都可以从this中拿到,然后我们用render函数return这一段jsx的代码,就可以被编译。
页面中使用:举个例子
<PMSelect
style="width: 215px"
defaultShowFirst={true}
on-change={$listeners.change}
{...{props: {selectOptions: periodList}}}
/>
这就是基本的一个流程,减少了很多代码,而且如果对react熟悉的话,很容易喜欢上这种开发方式。
下面记录一个问题:每个列表的一列都有这个下拉组件,但是如果我点击了某个选项,会跟前一列的值做一个对比,如果与之前的值不同的话,select背景会变色,这个就需要我们监听这个change事件,然后去修改对应的select框的样式,我们只能取配置文件里面修改这个样式,这样才不会跟其他的select互相影响,代码如下:
注意这里的h函数,将h
作为createElement
的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。从 Vue 的 Babel 插件的3.4.0 版本开始,我们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入const h = this.$createElement
,这样你就可以去掉(h)
参数了。对于更早版本的插件,如果h
在当前作用域中不可用,应用会抛错。
表头的配置文件:
const queryString = require('query-string')
import {stateDescShow} from '../../../service'
import getSelectJsx from './selectConfig'
let getJsx = (h, item, type) => {
let {sequenceNbr} = item
if (sequenceNbr === '0') {
return <span>{item[type] || '/'} </span>
}
return <span class="disabled-color">{item[type] || '/'}</span>
}
export default function (h, context) { // context在引用这个表头的时候由页面传入
return [
{
title: '所属部门',
customRender: item => {
return getJsx(h, item, 'depName')
}
},
{
title: '姓名',
customRender: item => {
return getJsx(h, item, 'name')
}
},
{
title: '职位',
customRender: item => {
return getJsx(h, item, 'positionName')
}
},
{
title: '职级',
customRender: item => {
return getJsx(h, item, 'jobLevel')
}
},
{
title: '自评等级',
customRender: item => {
return getJsx(h, item, 'selfRating')
}
},
{
title: '上评等级',
customRender: item => {
return getJsx(h, item, 'directLeaderRating')
}
},
{
title: '校准后等级',
width: '130px',
customRender: row => {
return getSelectJsx(h, row, context)
}
},
{
title: '当前阶段',
customRender: row => {
return (
<span>{stateDescShow(row)}</span>
)
}
}
]
}
表头使用:
![efd078740a7d74ac58395ecef910867b.png](https://img-blog.csdnimg.cn/img_convert/efd078740a7d74ac58395ecef910867b.png)
注意,把this.$createElement, this两个参数传进去
select的配置文件:
注意点: context从哪里来,怎么监听的change事件,怎么处理的原生dom,有的也可以用nativeOn监听事件,但是这里试了不行,on可以监听到 ,change事件的一个参数为value,第二个为event对象,可以拿到dom节点做操作,这样每个select点击都会被监听,然后判断处理值
import PMSelect from '../../../comp/PMSelect'
import { getDeptCalibrate, getCompanyCheck } from '../../../service/index'
// select是否显示
let getSelectJsx = (h, row, context) => {
const {
hasCalibrateAuth, // 是否有校准权限
getDeptcheckRight, // 是否到了部门校准阶段
ifSystermManager, // 是否是管理员
performEditShow // 详情是否到了150的校准阶段
} = context
let {sequenceNbr, performanceId} = row
let conf = config(context.ratingList, context, row)
if (sequenceNbr === '0') { // 表格列有数据
if (performanceId) { // 参与考评
if ((hasCalibrateAuth && getDeptcheckRight) || (ifSystermManager && performEditShow.state === 150)) { // 有校准权限
return h(PMSelect, { ...conf }, row)
} else {
// 判断部门校准这个有没有值
if ((!row.directLeaderRating && !row.calibrateRating) || !row.calibrateRating) return <span>/</span>
if (row.calibrateRating) {
if (row.calibrateRating === row.directLeaderRating) {
return <span>{row.calibrateRating}</span>
} else {
return <div class='callibrate_bg_color'>{row.calibrateRating}</div>
}
}
}
} else {
return <span>/</span>
}
}
return <span class="disabled-color">/</span>
}
function config (list, ctx, row) {
return {
props: {
selectOptions: list
},
attrs: {
defaultShowList: row.calibrateRating, // 测试回调值
defaultShowListFlag: true,
},
on: {
change (e, $event) {
// console.log('e,event', e, $event)
const { performanceId, directLeaderRating } = row
const {
hasCalibrateAuth,
getDeptcheckRight,
ifSystermManager,
performEditShow,
currentDeptTabId
} = ctx
let $elem = $event.context.$el.firstChild
if (e !== directLeaderRating) {
$elem.style.backgroundColor = 'rgba(255,125,65,0.10)'
$elem.style.border = '1px solid #FFCBB3'
$elem.firstChild.firstChild.style.color = '#FF7D41'
} else {
$elem.style.backgroundColor = ''
$elem.style.border = '1px solid #DDDFE4'
$elem.firstChild.firstChild.style.color = '#2D3040'
}
if (hasCalibrateAuth && getDeptcheckRight) { // 对个人进行校准
getDeptCalibrate({
rating: e,
performanceId: Number(performanceId),
deptId: currentDeptTabId.split('-')[1]
}).then(res => {
if (res.meta.code === 0) {
ctx.$message.success('调整成功', 1)
} else {
ctx.$message.error('调整失败', 1)
}
})
}
}
}
export default getSelectJsx
结果是:我改了某一个select,值有变化,就会变色:
![0df8bc16a923c7bd97fcd643c2fef89a.png](https://img-blog.csdnimg.cn/img_convert/0df8bc16a923c7bd97fcd643c2fef89a.png)
所以,vue的jsx写法在处理很多问题的时候还是很方便的,希望我们使用的越来越顺手。
感谢阅读。