在vue中使用jsx语法的使用方法


Posted in Javascript onSeptember 30, 2019

什么是JSX?

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

我为什么要在vue中用JSX?

想折腾一下呗,开玩笑.最开始是因为近期在学习react,在里面体验了一把jsx语法,发现也并没有别人说的很难受的感觉啊,于是就想尝试在vue中也试下,废话不多说,先来用代码来看下两者的区别吧.

ps:vue中大部分场景是不需要用render函数的,还是用模板更简洁直观.

使用template

// item.vue
<template>
 <div>
  <h1 v-if="id===1">
   <slot></slot>
  </h1>
  <h2 v-if="id===2">
   <slot></slot>
  </h2>
  <h3 v-if="id===3">
   <slot></slot>
  </h3>
  <h4 v-if="id===4">
   <slot></slot>
  </h4>
 </div>
</template>

<script>
  export default {
    name: "item",
    props:{
     id:{
      type:Number,
      default:1
     }
    }
  }
</script>

item组件中就是接收父组件传过来的id值来显示不同的h标签,v-if可以说用到了"极致",而且写了很多个冗余的slot

使用render函数和jsx

// item.vue
<script>
  export default {
    name: "item",
    props:{
     id:{
      type:Number,
      default:1
     }
    },
   render(){
     const hText=`
            <h${this.id}>${this.$slots.default[0].text}</h${this.id}>
           `
    return <div domPropsInnerHTML={hText}></div>
   }
  }
</script>

再加上父组件来控制props的值。父组件不做对比还用传统的template格式,

// list.vue
<template>
 <div>
  <h-title :id="id">Hello World</h-title>
  <button @click="next">下一个</button>
 </div>
</template>

<script>
 import Title from './item'

 export default {
  name: "list",
  data() {
   return {
    id:1
   }
  },
  components: {
   "h-title":Title
  },
  methods:{
   next(){
    ++this.id
   }
  }
 }
</script>

运行后页面就渲染出了h1 or h2 or h3标签,同时slot也只有一个,点击切换props的值,也会显示不同的h标签。第二种写法虽然不是很直接,但是省去了很多冗余代码,页面一下清爽了很多。

没了v-if,v-for,v-model怎么办?

不要着急,这些指令只是黑魔法,用js很容易实现。

v-if

render(){
    return (
     <div>
      {this.show?'你帅':'你丑'}
     </div>
    )
   }

写三元表达式只能写简单的,那么复杂的还得用if/else

render(){
    let ifText
    if(this.show){
      ifText=<p>你帅</p>
    }else{
      ifText=<p>你丑</p>
    }
    return (
     <div>
      {ifText}
     </div>
    )
   }

v-for

data(){
    return{
     show:false,
     list:[1,2,3,4]
    }
   },
   render(){
    return (
     <div>
      {this.list.map((v)=>{
       return <p>{v}</p>
      })}
     </div>
    )
   }

在jsx中{}中间是没办法写if/for语句的只能写表达式,所以就用map来当循环,用三元表达式来当判断了

v-model

最近在帮公司面试招人发现v-model很多人都不知道语法糖是什么?然后有些人说我可以用原生js实现,但是他们竟然不知道在vue中怎么实现,好吧,两个点:传值和监听事件改变值。

<script>
  export default {
    name: "item",
   data(){
    return{
     show:false,
     list:[1,2,3,4],
     text:'',
    }
   },
   methods:{
    input(e){
     this.text=e.target.value
    }
   },
   render(){
    return (
     <div>
      <input type="text" value={this.text} onInput={this.input}/>
      <p>{this.text}</p>
     </div>
    )
   }
  }
</script>

怎么用自定义组件?

很简单,只需要导入进来,不用再在components属性声明了,直接写在jsx中比如

<script>
 import HelloWolrd from './HelloWorld'
  export default {
   name: "item",
   render(){
    return (
      <HelloWolrd/>
    )
   }
  }
</script>

事件,class,style,ref等等怎么绑定?

来看下面的写法

render (h) {
 return (
  <div
   // normal attributes or component props.
   id="foo"
   // DOM properties are prefixed with `domProps`
   domPropsInnerHTML="bar"
   // event listeners are prefixed with `on` or `nativeOn`
   onClick={this.clickHandler}
   nativeOnClick={this.nativeClickHandler}
   // other special top-level properties
   class={{ foo: true, bar: false }}
   style={{ color: 'red', fontSize: '14px' }}
   key="key"
   ref="ref"
   // assign the `ref` is used on elements/components with v-for
   refInFor
   slot="slot">
  </div>
 )
}

上面有个地方需要注意,当给自定义组件绑定事件时用nativeOnClick,而模板格式是用
@click.native,另外当用到给函数式组件绑定事件时就有点小坑了下面说。

JSX中的函数式组件

函数式组件无状态,无this实例,下面是vue文档中提到的一段话:

因为函数式组件只是一个函数,所以渲染开销也低很多。然而,对持久化实例的缺乏也意味着函数式组件不会出现在 Vue devtools 的组件树里。

我个人理解因为没了状态(data),少了很多响应式的处理,还有生命周期等过程会提高速度和减少内存占用吧?
函数式组件也可以在模板格式中用只需要这样

<template functional>

</template>

那jsx中的函数式组件呢?也很简单只需增加配置functional: true就可以了

那函数式组件没有了this 实例怎么绑定事件怎么获取props呢?

组件需要的一切都是通过上下文传递,包括:

  • props : 提供所有 prop 的对象
  • children: VNode 子节点的数组
  • slots: 返回所有插槽的对象的函数
  • data:传递给组件的数据对象,并将这个组件作为第二个参数传入 createElement

上面我只列举了部分属性,这些是非函数式组件的东西,对于函数式组件
vue 增加了context对象,需要作为render(h,context) 第二个参数传入,this.$slots.default更新为context.children props原本是直接挂在this上的,现在变为context.props挂在了context.props上。this.data变为了context.data

需要注意的是对于函数式组件,没有被定义为prop的特性不会自动添加到组件的根元素上,意思就是需要我们手动添加到组件根元素了,看个例子吧

//父组件
 ...省略无关代码
 render(){
   return (
    <Item data={this.data} class="large"/>
   )
  }
//Item.vue组件
export default {
  functional:true,
   name: "item",
   render(h,context){
    return (
     <div class="red" >
      {context.props.data}
     </div>
    )
   }
  }

上面代码期待的是.large类名传入到了Item的根元素上,但是其实没有。我们需要增加点东西

// Item.vue
export default {
  functional:true,
   name: "item",
   render(h,context){
    return (
     <div class="red" {...context.data}>
      {context.props.data}
     </div>
    )
   }
  }

注意到,通过展开运算符把所有的属性添加到了根元素上,这个context.data就是你在父组件给子组件增加的属性,他会跟你在子元素根元素的属性智能合并,现在.large类名就传进来了。这个很有用,当你在父组件给子组件绑定事件时就需要这个了。下面说一个关于绑定事件的小坑

向 createElement 通过传入 context.data 作为第二个参数,我们就把 my-functional-button 上面所有的特性和事件监听器都传递下去了。事实上这是非常透明的,那些事件甚至并不要求 .native 修饰符

上面是vue官网的一段话,然而我看了一遍就忽略了一句很重要的话,就是最后一句,他说不需要.native修饰符了?好先看代码

// 父组件
 methods:{
   show(){
    alert('你好')
   }
  },
  render(){
   return (
    <Item data={this.data} onNativeClick={this.show} class="large"/>
   )
  }

上面代码乍一看没毛病,自定义组件用onNativeClick嘛,结果就是不会弹窗。唉,最后读了几遍刚才vue文档中的解释,才发现原来函数式组件不需要.native修饰符,对于template格式肯定一下就反应过来了,但是jsx的话,好吧,把上面的onNativeClick重新改为onClick就好了。

现有项目哪些功能可以用jsx代替呢?

这个其实跟最开始我例举的例子很像。我在项目中用它来干掉了满屏的v-if/v-else

由于我的业务是pad上的,需求是一套试卷有几十道题目,要求一屏只显示一道题目,点击下一题显示下一个题,思路也比较简单:

  1. 用一个num变量表示当前正在展示的题目索引
  2. 每次点击下一题按钮时num++
  3. 用v-if来判断 num===1,num===2这样来决定展示哪个。

这一写,模板里面好多啊,由于我们的题目每道题的模板可能都不一样,所以没办法循环,只能手写全部。之前考虑过用动态组件来切换,但是放弃了,因为没有if直观啊。

下面看怎么用jsx优化一下

//父组件
 export default {
  name: "list",
  data() {
   return {
    data:'我是函数式组件',
    id:1,
     tests:{
     1:<div><span>第一道题</span></div>,
     2:<div><section>第二道题</section></div>,
     3:<div><p>第三道题</p></div>
    }
   }
  },
  methods:{
   next(){
    ++this.id
   }
  },
  render(){
   return (
    <div>
     <Item data={this.tests[this.id]} class="large"/>
     <button onClick={this.next}>下一题</button>
    </div>
   )
  }
 }

上面每道题目的结构都不一致

//子组件,只接受数据展示,用函数式组件
<script>
 export default {
 functional:true,
  name: "item",
  render(h,context){
   return (
    <div class="red" {...context.data}>
     {context.props.data}
    </div>
   )
  }
 }
</script>

上面没有用任何if/else判断就完成了功能,这里用jsx我觉得比较合适,不知道各位大佬有什么其他思路?

最后

总结一下吧,我们平时开发还是多用temlate因为直观简洁,各种指令用着很方便,等你觉得用template写出的代码看着很冗余,或者想自己控制渲染逻辑比如循环,判断等等时可以考虑用JSX。另外推荐大家多用函数式组件提高性能。

第一次写文章,希望各位花时间看了的大佬觉得哪个说的不太严谨还需多多包涵,提出意见我都接受。

参考资料

vue 渲染函数&jsx
babel-plugin-transform-vue-jsx

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
niceTitle 基于jquery的超链接提示插件
May 31 Javascript
使用jQuery不判断浏览器高度解决iframe自适应高度问题
Dec 16 Javascript
jQuery操作JSON的CRUD用法实例
Feb 25 Javascript
基于jQuery实现仿QQ空间送礼物功能代码
May 24 Javascript
js canvas仿支付宝芝麻信用分仪表盘
Nov 16 Javascript
jquery与ajax获取特殊字符实例详解
Jan 08 Javascript
老生常谈javascript的面向对象思想
Aug 22 Javascript
给vue项目添加ESLint的详细步骤
Sep 29 Javascript
JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】
Mar 15 Javascript
jQuery实现的上传图片本地预览效果简单示例
Mar 29 jQuery
微信小程序中使用 async/await的方法实例分析
May 06 Javascript
javascript实现简易计算器功能
Sep 23 Javascript
微信小程序自定义tabBar在uni-app的适配详解
Sep 30 #Javascript
详解小程序云开发攻略(解决最棘手的问题)
Sep 30 #Javascript
webpack3升级到webpack4遇到问题总结
Sep 30 #Javascript
uploadify插件实现多个图片上传并预览
Sep 30 #Javascript
vue中使用[provide/inject]实现页面reload的方法
Sep 30 #Javascript
JavaScript中的null和undefined用法解析
Sep 30 #Javascript
vue resource发送请求的几种方式
Sep 30 #Javascript
You might like
PHPMailer安装方法及简单实例
2008/11/25 PHP
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2611816 bytes)
2014/11/08 PHP
隐藏Nginx或Apache以及PHP的版本号的方法
2016/01/03 PHP
PHPExcel笔记, mpdf导出
2016/05/03 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
thinkphp5.1框架中容器(Container)和门面(Facade)的实现方法分析
2019/08/05 PHP
yii2.0框架多模型操作示例【添加/修改/删除】
2020/04/13 PHP
jquery下操作HTML控件的实现代码
2010/01/12 Javascript
写了10年的Javascript也未必全了解的连续赋值运算
2011/03/25 Javascript
jquery中使用$(#form).submit()重写提交表单无效原因分析及解决
2013/03/25 Javascript
快速解决jQuery与其他库冲突的方法介绍
2014/01/02 Javascript
jQuery中Form相关知识汇总
2015/01/06 Javascript
分享12个非常实用的JavaScript小技巧
2016/05/11 Javascript
jQuery解决input元素的blur事件和其他非表单元素的click事件冲突问题
2016/08/15 Javascript
详解jQuery简单的表格应用
2016/12/16 Javascript
jQuery实现页面倒计时并刷新效果
2017/03/13 Javascript
React中常见的动画实现的几种方式
2018/01/10 Javascript
js中怎么判断两个字符串相等的实例
2019/01/17 Javascript
vue.config.js常用配置详解
2019/11/14 Javascript
[55:32]2018DOTA2亚洲邀请赛 4.4 淘汰赛 EG vs LGD 第二场
2018/04/05 DOTA
Python实现多进程共享数据的方法分析
2017/12/04 Python
python 利用栈和队列模拟递归的过程
2018/05/29 Python
flask session组件的使用示例
2018/12/25 Python
详解Html5微信支付爬坑之路
2018/07/24 HTML / CSS
你可能不熟练的十个前端HTML5经典面试题
2018/07/03 HTML / CSS
Hotter Shoes美国官网:英国最受欢迎的舒适鞋
2018/08/02 全球购物
美国儿童珠宝在线零售商:Loveivy
2019/05/22 全球购物
大学生评语大全
2014/04/18 职场文书
暑期社会实践心得体会
2014/09/02 职场文书
2014迎接教师节演讲稿
2014/09/10 职场文书
2014年社区国庆节活动方案
2014/09/16 职场文书
学生穿着不得体检讨书
2014/10/12 职场文书
2015年医院药剂科工作总结
2015/05/04 职场文书
幼儿园小朋友毕业感言
2015/07/30 职场文书
2019奶茶店创业计划书范本,值得你借鉴
2019/08/14 职场文书
详解Go语言运用广度优先搜索走迷宫
2021/06/23 Python