在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 相关文章推荐
纯JS实现动态时间显示代码
Feb 08 Javascript
模拟一个类似百度google的模糊搜索下拉列表
Apr 15 Javascript
jQuery实现列表内容的动态载入特效
Aug 08 Javascript
理解javascript正则表达式
Mar 08 Javascript
解析JavaScript实现DDoS攻击原理与保护措施
Dec 26 Javascript
jQuery实现单击按钮遮罩弹出对话框效果(2)
Feb 20 Javascript
Javascript中字符串相关常用的使用方法总结
Mar 13 Javascript
jQuery 防止相同的事件快速重复触发方法
Feb 08 jQuery
vue 过滤器filter实例详解
Mar 14 Javascript
JS中的算法与数据结构之二叉查找树(Binary Sort Tree)实例详解
Aug 16 Javascript
vue移动端弹起蒙层滑动禁止底部滑动操作
Jul 22 Javascript
如何理解Vue前后端数据交互与显示
May 10 Vue.js
微信小程序自定义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
第六节--访问属性和方法
2006/11/16 PHP
yii操作session实例简介
2014/07/31 PHP
PHP中使用curl入门教程
2015/07/02 PHP
浅谈php错误提示及查错方法
2015/07/14 PHP
php socket通信(tcp/udp)实例分析
2016/02/14 PHP
[原创]php实现 data url的图片生成与保存
2016/12/04 PHP
javascript 添加和移除函数的通用方法
2009/10/20 Javascript
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
用模版生成HTML的的框架jquery.tmpl使用详解
2015/01/07 Javascript
原生javascript实现图片滚动、延时加载功能
2015/01/12 Javascript
Linux下为Node.js程序配置MySQL或Oracle数据库的方法
2016/03/19 Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
2016/11/05 Javascript
bootstrap警告框使用方法解析
2017/01/13 Javascript
JS触摸事件、手势事件详解
2017/05/04 Javascript
浅谈Vue的加载顺序探讨
2017/10/25 Javascript
JavaScript中 ES6变量的结构赋值
2018/07/10 Javascript
vue $set 给数据赋值的实例
2019/11/09 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
2020/08/03 Javascript
js前端对于大量数据的展示方式及处理方法
2020/12/02 Javascript
python中的随机函数小结
2018/01/27 Python
python通过elixir包操作mysql数据库实例代码
2018/01/31 Python
matplotlib调整子图间距,调整整体空白的方法
2018/08/03 Python
python生成九宫格图片
2018/11/19 Python
python读csv文件时指定行为表头或无表头的方法
2019/06/26 Python
python中count函数简单的实例讲解
2020/02/06 Python
基于python实现生成指定大小txt文档
2020/07/20 Python
python对输出的奇数偶数排序实例代码
2020/12/04 Python
手把手教你实现一个canvas智绘画板的方法
2019/03/04 HTML / CSS
美国精品家居用品网站:US-Mattress
2016/08/24 全球购物
德国古洛迷亚百货官网:GALERIA Kaufhof
2017/06/20 全球购物
金融事务专业求职信
2014/04/25 职场文书
2014年扶贫帮困工作总结
2014/12/09 职场文书
共青团员自我评价
2015/03/10 职场文书
盗窃罪辩护词范文
2015/05/21 职场文书
工作违纪的检讨书范文
2019/07/09 职场文书
个人工作总结(管理人员)范文
2019/08/13 职场文书