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. 如何在 Vue 项目中优雅地使用图标

    1. 字体图标与矢量图标 目前主要有两种图标类型:字体图标和矢量图标. 字体图标是在网页打开时,下载一整个图标库,通常可以通过特定标签例如 <i> 来使用,优点是方便地实现文字混排,缺点是 ...

  2. webgl智慧楼宇发光系列之线性采样下高斯模糊

    目录 webgl智慧楼宇发光系列之线性采样下高斯模糊 效率问题 线性采样 代码讲解 总结 参考文档 webgl智慧楼宇发光系列之线性采样下高斯模糊 前面一篇文章 <webgl智慧楼宇发光效果算法 ...

  3. mysql order by 造成语句 执行计划中Using filesort,Using temporary相关语句的优化解决

    mysql> explain  select permission.* from t_rbac_permission   permission  inner JOIN  t_rbac_acl   ...

  4. 在缩小浏览器宽度的时候,图片会超出li的宽度

    要确保在缩小浏览器宽度时,图片不会超出 <li> 元素的宽度,您可以为描述文本添加一些样式,以便让图片适应于 <li> 元素.一种常见的方法是使用 CSS 中的 max-wid ...

  5. oeasy教您玩转vim - 59 - # 编辑总结

    ​ [Github地址] (https://github.com/overmind1980/oeasyvim) [Gitee地址] (overmind1980/oeasyvim) [蓝桥实验楼 邀请码 ...

  6. CSP2023

    坐标HA 背景 NOIP都打完了,CSP-S都没写游记,所以来补一篇(逃-- 正文 Day 7*-1 考前一周停课集训,被whk老师怒斥不务正业,悲QWQ. Day 0 周五得到年级第一zyx的鼓励, ...

  7. vue小知识~使用$attrs和$listeners接收父组件转来的属性和方法

    一般下我们子组件获取父组件传过来的的值得时候,我们是使用props来接收,但是如果我们父组件转过来的值是给孙组件使用时,使用哪个props接收的方式太过麻烦. 这是vue为我们提供了一个实例$attr ...

  8. 12、SpringMVC之拦截器

    12.1.环境搭建 创建名为spring_mvc_interceptor的新module,过程参考9.1节和9.5节 12.1.1.页面请求示例 <a th:href="@{/test ...

  9. 【MongoDB】Re05 分片集群(Win平台搭建)

    分片副本集1 (3实例)  主1 从1 裁1 分片副本集2 (3实例)  主1 从1 裁1 配置副本集(3实例) 主1 从2 路由(2配置) 用Windows平台搭建 配置目录设置: ├─config ...

  10. 【SVN】文件解锁

    提交代码莫名其妙的把文件上锁了 然后找到文件右键的SVN的选项也不能解锁: 原来是这样解锁的: 对上锁文件的所在目录右键找到SVN选项 然后勾选第二项: 这样就解锁了.如果还说没有解锁,说明是对方自己 ...