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. ARP协议介绍与投毒攻击

    目录 ARP是什么? ARP协议工作原理 ARP攻击原理 攻击软件 防范 Reference ARP是什么? ARP是通过网络地址(IP)来定位机器MAC地址的协议,它通过解析网络层地址(IP)来找寻 ...

  2. mysql大数据表添加字段

    方案一.老表数据迁移四部曲方案1.新建老表t_order_goods的备份表t_order_goods_bak,同时加一个字段:isVirtual 并给默认值2.迁移老表t_order_goods数据 ...

  3. IPv6、双栈与隧道

    双栈策略 实现IPv6结点与IPv4结点互通的最直接的方式是在IPv6结点中加入IPv4协议栈.具有双协议栈的结点称作"IPv6/v4结点",这些结点既可以收发IPv4分组,也可以 ...

  4. [oeasy]python0135_命名惯用法_name_convention

    命名惯用法 回忆上次内容 上次 了解了isidentifier的细节 关于 关键字 关于 下划线   如何查询 变量所指向的地址? id   如何查询 已有的各种变量? locals   如果 用一个 ...

  5. Pandas库学习笔记(6) -- Pandas 基本方法

    Pandas 基本方法实例 到目前为止,我们了解了三个Pandas DataStructures以及如何创建它们.由于它在实时数据处理中的重要性,因此我们将主要关注DataFrame对象,并讨论其他一 ...

  6. JDBC第一天:JDBC的基础

    第一,JDBC叫java数据库连接技术,是用来实现数据库的增.删.改.查的接口技术. 第二,实现数据库的连接步骤:在这之前需要导包 1,准备四大参数 a,,准备驱动类:driverClassName: ...

  7. Python版RNA-seq分析教程:差异表达基因分析

    Bulk RNA-seq 分析的一个重要任务是分析差异表达基因,我们可以用 omicverse包来完成这个任务.对于差异表达分析而言,首先,我们可> 以先将 gene_id 改为 gene_na ...

  8. 解锁Nginx日志的宝藏:GoAccess——你的实时、交互式Web日志分析神器!

    在当今数字化的时代,网站的流量和用户行为数据就像是一座蕴藏着无尽秘密的宝藏.而如何有效地挖掘和分析这些数据,成为了许多网站管理者和开发者头疼的问题.GoAccess,一款开源的实时Web日志分析工具, ...

  9. 记一次springboot整合rabbitMQ的list序列化问题

    问题:平时传一个类的时候都会继承Serializable实现正确传输,这次我把list<Object>直接丢成了message,导致rabbitMQ不能序列化对象.报错 org.sprin ...

  10. 关于android的图像视图的基本了解

    最好直接复制进去而不是拖进去 图片直接导入最好用小写字母命名,数字与字母之间要用_,而且数字好像不可以连用 centerInside,fitCenter,center的区别: centerInside ...