在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 相关文章推荐
jQuery+css3实现文字跟随鼠标的上下抖动
Jul 31 Javascript
Knockout自定义绑定创建方法
Dec 26 Javascript
prototype.js常用函数详解
Jun 18 Javascript
jQuery实现的兼容性浮动层示例
Aug 02 Javascript
Node.js 8 中的 util.promisify的详解
Jun 12 Javascript
jQuery序列化后的表单值转换成Json
Jun 16 jQuery
动态内存分配导致影响Javascript性能的问题
Dec 18 Javascript
微信小程序如何实现全局重新加载
Jun 05 Javascript
js使用文件流下载csv文件的实现方法
Jul 15 Javascript
JavaScript使用表单元素验证表单的示例代码
Aug 20 Javascript
基于JavaScript实现十五拼图代码实例
Apr 26 Javascript
vue prop传值类型检验方式
Jul 30 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
获取远程文件大小的php函数
2010/01/11 PHP
php魔术变量用法实例详解
2014/11/13 PHP
PHP+redis实现添加处理投票的方法
2015/11/14 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
Thinkphp 框架扩展之类库扩展操作详解
2020/04/23 PHP
jquery构造器的实现代码小结
2011/05/16 Javascript
JavaScript实现梯形乘法表的方法
2015/04/25 Javascript
javascript中返回顶部按钮的实现
2015/05/05 Javascript
基于Jquery实现焦点图淡出淡入效果
2015/11/30 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
jQuery实用小技巧_输入框文字获取和失去焦点的简单实例
2016/08/25 Javascript
基于js中的存储键值对以及注意事项介绍
2018/03/30 Javascript
JavaScript数据结构与算法之基本排序算法定义与效率比较【冒泡、选择、插入排序】
2019/02/21 Javascript
node命令行工具之实现项目工程自动初始化的标准流程
2019/08/12 Javascript
详解利用eventemitter2实现Vue组件通信
2019/11/04 Javascript
vue.config.js常用配置详解
2019/11/14 Javascript
Vue+ElementUI table实现表格分页
2019/12/14 Javascript
JS实现拖动模糊框特效
2020/08/25 Javascript
Python通过正则表达式选取callback的方法
2015/07/18 Python
全面了解Python的getattr(),setattr(),delattr(),hasattr()
2016/06/14 Python
Python读取图片属性信息的实现方法
2016/09/11 Python
pandas 实现将重复表格去重,并重新转换为表格的方法
2018/04/18 Python
Python 访问限制 private public的详细介绍
2018/10/16 Python
python实现一个函数版的名片管理系统过程解析
2019/08/27 Python
匡威比利时官网:Converse Belgium
2017/04/13 全球购物
屈臣氏乌克兰:Watsons UA
2019/10/29 全球购物
社区中秋节活动方案
2014/01/29 职场文书
师范学院美术系毕业生自我鉴定
2014/01/29 职场文书
食品厂厂长岗位职责
2014/01/30 职场文书
人资专员岗位职责
2014/04/04 职场文书
竞选副班长演讲稿
2014/04/24 职场文书
医院院务公开实施方案
2014/05/03 职场文书
幼儿园端午节活动方案
2014/08/25 职场文书
2015大学生党员自我评价范文
2015/03/03 职场文书
浅谈Python类的单继承相关知识
2021/05/12 Python
JAVA 线程池(池化技术)的实现原理
2022/04/28 Java/Android