摘要:JSX是一种Javascript的语法扩展,JSX = Javascript + XML,即在Javascript里面写XML,因为JSX的这个特性,所以它既具备了Javascript的灵活性,同时又兼具html的语义化和直观性。
本文营养来自->在 Vue 中如何使用 JSX,就这么简单!【建议收藏】
探索BG:项目中有个自定义表格以及表单加载和显示,考虑到使用JSX
在Vue中使用JSX,需要使用Babel插件
vue create vue-jsx
#选择vue2
安装依赖
npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
# or
yarn add @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
配置.babelrc(babel.config.js)
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
[
'@vue/babel-preset-jsx',
{
'injectH: false
}
]
]
}
配置了babel.config.js后,我们把正常引用的组件如HelloWorld.vue 改为HelloWorld.js,并且删除文件中关于template和style,以及script标签
项目中不是采取配置babel的方式,而是采用vue组件创建的方式,如下
步骤一、通过install函数 Vue.component注入组件
步骤二、Vue.use初始化自定义组件
步骤三、要使用的组件页面中直接引用
1、纯文本、动态内容、标签使用、自定义组件、样式和class
import myComponent from './myComponent'
import './HelloWorld.css'
// 创建一个组件button
const ButtonCounter = {
name: "button-counter",
props: ["count"],
methods: {
onClick() {
this.$emit("change", this.count + 1);
}
},
render() {
return (
<button onClick={this.onClick}>数量 {this.count}+</button>
);
}
};
export default {
name: 'HelloWorld',
components: {
myComponent
},
data () {
return {
text:'hello 纸没了飞机',
inputText:'我吃了',
count: 0
}
},
props: {
msg: String
},
watch: {},
methods: {
onChange(val) {
this.count = val;
alert(this.count)
}
},
render() {
// const {text,inputText,count} = this //通过解构,下方return片段中就不需要this
return (
<div>
<h3>内容</h3>
{/* 纯文本 */}
<p>hello, I am Gopal</p>
{/* 动态内容 */}
<p>{ this.text }</p>
<p>hello { this.msg }</p>
{/* 输入框 */}
<input/>
{/* 自定义组件 */}
<myComponent/>
<ButtonCounter
style={{ marginTop: "10px" }}
count={this.count}
type="button"
onChange={this.onChange}
/>
</div>
);
}
}
2、条件渲染
jsx本身也是个条件表达式,不再需要使用v-if指令
(1) 使用if/else
const element = (name) => {
if (name) {
return <h1>Hello, { name }</h1>
} else {
return <h1>Hello, Stranger</h1>
}
}
等效于:
const element = (name) => <h1>Hello, { name || 'Stranger' }</h1>
(2)使用三目运算符
const element = (name) => <h1>Hello, { name || 'Stranger' }</h1>
等效于:
const element = (name) => <h1>Hello, { name || 'Stranger' }</h1>
3、列表渲染
const list = [
{id: 1,name: '张三'},
{id: 2,name: '李四'}
]
const element = list.map(item => {
return <div>{ item.name }</div>
})
4、标签属性绑定
属性绑定也是使用花括号,不需要使用v-bind指令
const href = 'https://devui.design/'
const element = <a href={href}> Design </a>
5、class类名绑定
直接使用JS模板字符串:
const element = <div className={`devui-accordion-item-title ${ disabled ? 'disabled' : ''}`}></div>
也可以使用数组:
const element = <div class = {['devui-accordion-item-title', disabled && 'disabled']}></div>
6、style样式绑定
使用双花括号:
const width = '100px'
const element = <button style={{with, fontSize: '16px'}}></button>
7、事件绑定
绑定事件使用单花括号,注意事件名前加on前缀,如click事件要写成onClick, mouseenter事件携程onMouseenter
const confirm = () => {}
<button onClick={confirm}>确定</button>
如果需要携带参数,要使用箭头函数包裹:
jsx中给事件增加修饰符需要借助withModifiers方法
import { withModifiers, defineComponent, ref } from 'vue'
const App = defineComponent({
setup() {
const count = ref(0);
const inc = () => {
count.value++;
};
return () => (
<div onClick={ withModifiers(inc, ['self']) }>{ count.value }</div>
);
},
})
注意:Vue模板中ref变量是可以直接解构的,但是再jsx中不行,需要记得添加==.value==,比如上面的=={ count.value }==
8、v-model双向绑定
(1) 绑定modelValue
(2) 绑定自定义名称
比如绑定visible, JSX中不能直接使用v-model:visible的语法,需要传入一个数组[menuShow.value, ‘visible’], 数组的第二个参数就是要绑定的自定义名称
9、插槽
插槽就是子组件中提供给父组件使用的一个占位符,插槽分为默认插槽,具名插槽和作用域插槽
(1) 使用默认插槽
使用element-ui的Dialog时,弹窗内容就是用了默认插槽,在JSX中使用默认插槽的用法与普通插槽的用法基本一致:
render(){
return (
<ElDialog title="标题" visible={true}>
{/*这里是默认插槽*/}
<div>弹窗内容</div>
</ElDialog>
)
}
(2) 自定义默认插槽
在Vue实例this上有个属性slots,这个上面挂载了这个组件内部所有插槽,使用this.$slots.default就可以将默认插槽加入到组件内
export default {
props: {
visible: {
type: Boolean,
default: false
}
},
rendere() {
return (
<div class="custom-dialog" vShow={this.visible}>
{ this.$slots.default }
</div>
)
}
}
使用:
<myComponet visible={true} slot>我是自定义默认插槽myComponet>
(3) 具名插槽
当一个组件需要多个插槽时,为了区分 就给插槽起名,如element-ui弹窗可以自定义底部按钮区内容,就是用了名为footer的插槽
render() {
return (
<ElDialog title="标题" visible={true}>
<div>内容</div>
<template slot="footer">
<ElButton>确定</ElButton>
<ElButton>取消</ElButton>
</template>
</ElDialog>
)
}
(4) 自定义具名插槽
render() {
return (
<div class="custom-dialog" vShow={this.visible}>
{this.$slots.default}
{/*自定义具名插槽*/}
<div class="custom-dialog_footer">{this.$slots.footer}</div>
</div>
)
}
使用:
<myComponent visible={true}>
<template slot="footer">
<ElButton>确定ElButton>
<ElButton>取消ElButton>
template>
myComponent>
(5) 作用域插槽
有时候插槽内容能够访问子组件中才有的数据时很有用的,这时就需要用到作用域插槽,在JSX中,因为没有v-slot指令,所以作用域插槽的使用方式与模板代码里面的方式不同了
比如在element-ui中,我们使用el-table时可以自定义表格单元格的内容,此时就用到作用域插槽
{
// 这个user就是子组件传递来的数据,同理可拿到el-table的row,不过test得是default
common on!{user.name},这是作用域插槽
}
}
}}>
(6) 自定义作用域插槽
子组件中通过{this.$scopedSlots.test({ user: {name: ‘纸飞机’}})} 指定插槽名称是test,并将user传递给父组件;父组件在书写子组件标签的时候,通过scopedSlots值指定插入的位置是test,并在回调函数获取到子组件传入user值
注意:作用域插槽是写在子组件标签中,类似属性 而不是像具名插槽放在标签内部
export default {
name: 'slotComponent',
data() {
return {}
},
props: {
visible: {
type: Boolean,
default: false
},
listData: {
type: Array,
default: function () {
return []
}
}
},
render() {
return (
<div vShow={this.visible}>
{/*自定义作用域插槽*/}
<div class="item">
{
this.$scopedSlots.test({
user: {name: '纸飞机'}
})
}
</div>
</div>
)
}
}