VUE高阶------使用JSX语法【转载】

什么是JSX?

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

对于h参数

h 做为 createElement 的别名是 Vue 生态系统中的一个通用惯例,实际上也是 JSX 所要求的。从 Vue 的 Babel 插件的 3.4.0 版本开始,咱们会在以 ES2015 语法声明的含有 JSX 的任何方法和 getter 中 (不是函数或箭头函数中) 自动注入 const h = this.$createElement,这样你就能够去掉 (h) 参数了。对于更早版本的插件,若是 h 在当前做用域中不可用,应用会抛错。
vue

安装

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props复制代码

修改.babelrc配置

{
  "presets": ["@vue/babel-preset-jsx"]
}复制代码

使用render函数和jsx

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

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

// list.vue
<template>
 <div> <h-title :id="id">Hello World</h-title> </div> </template>

<script>
 import Title from './item'

 export default {
   components: {
     "h-title":Title
   }
 }
</script>复制代码


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

  • v-if
render(){
       return (
         <div> {this.show?'是':'否'} </div>
       )
     }复制代码

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

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来当循环,用三元表达式来当判断了github

  • v-modelnpm

<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等等怎么绑定?

来看下面的写法bash

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,另外当用到给函数式组件绑定事件时就有点小坑了下面说。babel

JSX中的函数式组件

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

由于函数式组件只是一个函数,因此渲染开销也低不少。然而,对持久化实例的缺少也意味着函数式组件不会出如今 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我以为比较合适,不知道各位大佬有什么其余思路?

最后

这是转载一位大佬的博客

做者:SuperMan一路向北
来源:掘金
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。
相关文章
相关标签/搜索