JSX是什么?

JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性。

注:灵活度强的部分组件可以用JSX来代替,整个工程没有必要都使用JSX。

vue工程配置JSX相关插件

我们一般使用的渲染函数时这样的:

createElement(
'anchored-heading', {
props: {
level: 1
}
}, [
createElement('span', 'Hello'),
' world!'
]
)

对应的模板如下:

<anchored-heading :level="1">
<span>Hello</span> world!
</anchored-heading>

如果这样使用原生的方式来写比较麻烦,那么我可以借助babel插件。

如果是babel7.x那么需要安装如下插件

npm i @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props -D

配置的babel.config.js:

module.exports = {
presets: [
[
'@vue/babel-preset-jsx',
{
vModel: false,
compositionAPI: true,
},
],
],
}

如果是babel6.x那么需要安装如下插件

npm install\
babel-plugin-syntax-jsx\
babel-plugin-transform-vue-jsx\
babel-helper-vue-jsx-merge-props\
babel-preset-env\
--save-dev

.babelrc:

{
"presets": ["env"],
"plugins": ["transform-vue-jsx"]
}

如果使用的vuecli2脚手架,那么默认安装了babel6.x相关的插件,不需要再重复安装。

详细可参考:《jsx-vue2》

JSX基础用法

我们新建一个HelloWorld组件,以前都是HelloWorld.vue的文件,现在我们可以使用HelloWorld.js来创建这个组件,下面以HelloWorld组件为例进行讲解。

自定义组件

我们在HelloWorld组件中也可以使用自定义的组件,HelloWorld.js代码如下:

const ButtonCounter = {
name: "button-counter",
props: ["count"],
methods: {
onClick() {
this.$emit("changeNum", this.count + 1);
}
},
render() {
return <button onClick={this.onClick}>数量:{this.count}</button>;
}
}; export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
count: 0
};
},
methods: {
// 改变button按钮数量
changeNum(val) {
this.count = val;
}
},
render() {
const { count } = this; // 解构
return (
<div class="hello-world-content">
<ButtonCounter style={{ marginTop: "20px" }} count={count} onChangeNum={this.changeNum}></ButtonCounter>
</div>
);
}
};

普通属性、行内样式、动态class与style

const ButtonCounter = {
name: "button-counter",
props: ["count"],
methods: {
onClick() {
this.$emit("changeNum", this.count + 1);
}
},
render() {
return <button onClick={this.onClick}>数量:{this.count}</button>;
}
}; export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
count: 0,
text: "Hello World!",
msgClass: "msg-class",
isGreen: true
};
},
methods: {
// 改变button按钮数量
changeNum(val) {
this.count = val;
}
},
render() {
const { count, text } = this; // 解构
return (
<div class="hello-world-content">
<p style="color:red">{text}</p>
<p class={this.msg ? this.msgClass : ""}>动态绑定class,传递过来的消息:{this.msg}</p>
<p style={this.isGreen ? "color: green" : ""}>动态绑定style,传递过来的消息:{this.msg}</p>
<input placeholder="placeholder属性"></input>
<ButtonCounter style={{ marginTop: "20px" }} count={count} onChangeNum={this.changeNum}></ButtonCounter>
</div>
);
}
};

展示效果:

DOM渲染结构如下:

常用指令

v-html、v-if、v-for、v-model常用指令在JSX中无法使用,需要使用其他方式来实现。

v-html

在JSX中,如果要设置DOM的innerHTML,需要用到domProps

组件使用:

<HelloWorld msg="<div class='custom-div'>这是自定义的DOM</div>"> </HelloWorld>

组件代码:

export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {};
},
methods: {},
render() {
return <div domPropsInnerHTML={this.msg}></div>;
}
};

渲染DOM结果:

v-for

使用map来实现:

render() {
const list = [1,2,3]
return(
<div>
{ list.map(item => <button>按钮{item}</button>) }
</div>
)
}

v-if

简单示例:

render() {
const bool = false;
return <div>{bool ? <button>按钮1</button> : <button>按钮2</button>}</div>;
}

复杂示例:

render() {
let num = 3
if(num === 1){ return( <button>按钮1</button> ) }
if(num === 2){ return( <button>按钮2</button> ) }
if(num === 3){ return( <button>按钮3</button> ) }
}

v-model

注:新版 vue-cli4 中,已经默认集成了 JSX 语法对 v-model 的支持,可以直接使用

<input v-model={this.value}>

如果是老项目比如脚手架vuecli2,那么需要安装插件babel-plugin-jsx-v-model,同时在.babelrc文件中加入如下插件配置:

"plugins": ["jsx-v-model"]

使用示例:

export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
value: "abc"
};
},
watch: {
value(val) {
console.log("this.model内容:" + val);
}
},
methods: {},
render() {
return (
<div>
<input v-model={this.value} placeholder="普通文本" />
</div>
);
}
};

监听事件、事件修饰符

监听事件

监听事件想到用 onChange, onClick等。

需要注意的是,传参数不能使用 onClick={this.handleClick(params)},这样子会每次 render 的时候都会自动执行一次方法。

应该使用 bind,或者箭头函数来传参。

组件示例代码:

export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {};
},
methods: {
handleClick(val) {
alert(val);
}
},
render() {
return (
<div>
<button type="button" onClick={this.handleClick.bind(this, 11)}>
方式一
</button>
<button type="button" onClick={() => this.handleClick(22)}>
方式二
</button>
</div>
);
}
};

用监听事件来实现v-model:

methods: {
input(e) {
this.value = e.target.value;
}
},
render() {
return (
<div>
<input type="text" value={this.value} onInput={this.input} />
</div>
);
}

也可以调整为:

<input type="text" value={this.value} onInput={(e) => (this.vaue = e.target.value)} />

还可以使用对象的方式去监听事件:

export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
value: ""
};
},
watch: {
value(val) {
console.log("this.model的内容:" + val);
}
},
methods: {
handleInput(e) {
this.value = e.target.value;
},
handleFocus(e) {
console.log(e.target);
}
},
render() {
return (
<div>
<input type="text" value={this.value} {...{ on: { input: this.handleInput, focus: this.handleFocus } }} />
</div>
);
}
};

nativeOn仅对于组件,用于监听原生事件,也可以使用对象的方式去监听事件:

{...{nativeOn:{click: this.handleClick}}}

事件修饰符

和指令一样,除了个别的之外,大部分的事件修饰符都无法在JSX中使用。

  • .stop : 阻止事件冒泡,在JSX中使用event.stopPropagation()来代替
  • .prevent:阻止默认行为,在JSX中使用event.preventDefault() 来代替
  • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调,使用下面的条件判断进行代替
if (event.target !== event.currentTarget){
return
}

.enter与keyCode: 在特定键触发时才触发回调

if(event.keyCode === 13) {
// 执行逻辑
}

除了上面这些修饰符之外,尤大大对于.once,.capture,.passive,.capture.once做了优化,简化代码:

export default {
name: "HelloWorld",
props: {
msg: String
},
methods: {
handleClick(e) {
console.log("click事件:" + e.target);
},
handleInput(e) {
console.log("input事件:" + e.target);
},
handleMouseDown(e) {
console.log("mousedown事件:" + e.target);
},
handleMouseUp(e) {
console.log("mouseup事件" + e.target);
}
},
render() {
return (
<div
{...{
on: {
// 相当于 :click.capture
"!click": this.handleClick,
// 相当于 :input.once
"~input": this.handleInput,
// 相当于 :mousedown.passive
"&mousedown": this.handleMouseDown,
// 相当于 :mouseup.capture.once
"~!mouseup": this.handleMouseUp
}
}}
>
点击模块
</div>
);
}
};

结合第三方UI库组件

不仅仅在 render 函数里面使用 JSX,而且还可以在 methods 里面返回 JSX,然后在 render 函数里面调用这个方法。并且也可以直接使用例如elementui等ui组件。

示例:

export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
visible: false
};
},
methods: {
renderFooter() {
return (
<div>
<el-button onClick={() => (this.visible = false)}>确定</el-button>
<el-button onClick={() => this.closeDialog()}>取消</el-button>
</div>
);
},
openDialog() {
this.visible = true;
},
closeDialog() {
this.visible = false;
}
},
render() {
const footerHTML = this.renderFooter();
return (
<div>
<button onClick={() => this.openDialog()}>打开弹框</button>
<el-dialog visible={this.visible} title="弹框提示" width="200px" show-close={true} before-close={() => (this.visible = false)}>
<div>弹框内容</div>
<template slot="footer">{footerHTML}</template>
</el-dialog>
</div>
);
}
};

效果图:

插槽

普通插槽与具名插槽

示例:

<HelloWorld>
<template slot="default">默认内容</template>
<template slot="footer">
<el-button type="primary">确定</el-button>
<el-button>取消</el-button>
</template>
</HelloWorld>

HelloWorld组件代码:

export default {
name: "HelloWorld",
render() {
return (
<div>
<div class="default">{this.$slots.default}</div>
<div class="footer">{this.$slots.footer}</div>
</div>
);
}
};

作用域插槽

示例:

<HelloWorld>
<template v-slot:content="{ name, age }">
<div>姓名:{{ name }}</div>
<div>年龄:{{ age }}</div>
</template>
</HelloWorld>

HelloWorld组件代码:

export default {
name: "HelloWorld",
render() {
return (
<div>
<div class="content">{this.$scopedSlots.content({ name: "张三", age: 20 })}</div>
</div>
);
}
};

子组件通过{this.$scopedSlots.content({ name: "张三", age: 20 })}指定插槽的名称为content,并将含有name,age属性的对象数据传递给父组件,父组件就可以在插槽内容中使用子组件传递来的数据。

参考:

vue中如何使用JSX?的更多相关文章

  1. 在Vue中使用JSX,很easy的

    摘要:JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javasc ...

  2. 在vue中使用jsx语法

    什么是JSX? JSX就是Javascript和XML结合的一种格式.React发明了JSX,利用HTML语法来创建虚拟DOM.当遇到<,JSX就当HTML解析,遇到{就当JavaScript解 ...

  3. vue中使用jsx

    vue中使用jsx 为什么需要使用jsx呢?这个需要搞清楚 其实vue官方也说了,对于那些非常多v-if v-else的情况,就可以尝试使用render函数或者jsx,不过render函数写简单的结构 ...

  4. vue中使用JSX报错,如何解决

    Support for the experimental syntax 'jsx' isn't currently enabled (32:12): 30 | }, 31 | render() { & ...

  5. 记录在vue中使用jsx时踩过的坑

    使用方法及细节就不一一说了. 1.给input或者textarea绑定value时,出现失效的问题.解决方法:https://github.com/vuejs/babel-plugin-transfo ...

  6. Vue 中渲染字符串形式的组件标签

    在vue中如果要渲染字符串形式的标签,vue 提供了 v-html 指令,可以很方便的渲染出来.但是如果这个标签是一个组件,或者element-ui 的组件时,就不能解析出来了,因为v-html 只能 ...

  7. vue中的页面渲染方案

    一.模板渲染 <div id="J_render_app"> <ul v-if="items.length"> <li v-for ...

  8. 理解MVVM在react、vue中的使用

    理解MVVM在react.vue中的使用 一:什么是MVC.为什么不用MVC 1:MVC的含义: M(modal):是应用程序中处理数据逻辑的部分. V (view)  :是应用程序中数据显示的部分. ...

  9. vue用template还是JSX?

    各自特点 template 模板语法(HTML的扩展) 数据绑定使用Mustache语法(双大括号) <span>{{title}}<span> JSX JavaScript的 ...

  10. TS 基础及在 Vue 中的实践:TypeScript 都发布 5.0 版本啦,现在不学更待何时!

    大家好,我是 Kagol,OpenTiny 开源社区运营,TinyVue 跨端.跨框架组件库核心贡献者,专注于前端组件库建设和开源社区运营. 微软于3月16日发布了 TypeScript 5.0 版本 ...

随机推荐

  1. Vscode连接虚拟机报错

    Vscode 连接虚拟机报错问题解决 问题解释 Permission denied, please try again.出现这个问题通常表示身份验证失败. 可能的原因有 SSH用户密码错误 SSH端口 ...

  2. Simple WPF: S3实现MINIO大文件上传并显示上传进度

    最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园. 创作不易,如果觉得有用请在Github上为博主点亮一颗小星星吧! 目的 早两天写了一篇S3简单上传文件的小工具,知乎上看到了一个问题 ...

  3. 用户数据报协议UDP

    UDP的首部格式如下: (1) 源端口,源端口号.在需要对方回信时选用.不需要时可用全0. ⑵目的端口,目的端口号.这在终点交付报文时必须使用. ⑶长度,UDP用户数据报的长度,其最小值是8(仅有首部 ...

  4. PN转Modbus RTU模块连接ACS4QQ变频器通信

    一台完整的机器在出厂前由许多部件组成.但是,由于各种原因,这些组件来自不同的制造商,导致设备之间的通信协议存在差异.Modbus和Profinet代表两种不同的通信协议,Profinet通常用于较新的 ...

  5. oeasy教您玩转vim - 11 - # 向前向后

    向前向后 回忆上节课内容 我们上次强化了起手势 回忆了基本的移动方式 hjkl 除 hjkl 外,据说还有更厉害的移动方式 是什么呢? 下素材 #这个素材,我们下载过,重温一下 wget github ...

  6. C#全局键盘监听(Hook)的使用

    一.为什么需要全局键盘监听? 在某些情况下应用程序需要实现快捷键执行特定功能,例如大家熟知的QQ截图功能Ctrl+Alt+A快捷键,只要QQ程序在运行(无论是拥有焦点还是处于后台运行状态),都可以按下 ...

  7. SQL Server 清除一个数据库下所有表数据,保留表结构

    用法:在需要清空数据的数据库创建并执行存储过程,该存储过程并不会影响其他数据库 请小心使用这些脚本,确保在生产环境之前备份您的数据库.️ 存储过程: CREATE PROCEDURE ClearAll ...

  8. 火山引擎VeDI数据技术分享:两个步骤,为Parquet降本提效

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 作者:王恩策.徐庆 火山引擎 LAS 团队 火山引擎数智平台 VeDI 是火山引擎推出的新一代企业数据智能平台,基 ...

  9. 【Project】JS的Map对象前后交互问题

    这是我在项目中写的一个Map对象: let map = new Map(); for (let i = 0; i < type_checked_value.length; i++) { let ...

  10. 最快视频转绘-AnimateDiff-Lightning

    最快视频转绘-AnimateDiff-Lightning Video-to-Video Generation AnimateDiff-Lightning 非常适合视频到视频的生成.使用 Control ...