Vue render 函数和JSX语法的使用

基本使用

Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。

让我们深入一个简单的例子,这个例子里 render 函数很实用。假设我们要根据父组件传过来的数据决定显示哪个标签:

父组件:

<template>
  <div id="app">
    <level type="1">hello world</level>
    <level type="2">hello world</level>
    <level type="3">hello world</level>
    <level type="4">hello world</level>
  </div>
</template>

<script>
import Level from './components/Level'

export default {
  name: 'App',
  components: {
    Level
  }
}
</script>

Level组件:

<template>
    <div>
        <h1 v-if="type == 1"><slot></slot></h1>
        <h2 v-else-if="type == 2"><slot></slot></h2>
        <h3 v-else-if="type == 3"><slot></slot></h3>
        <h4 v-else-if="type == 4"><slot></slot></h4>
    </div>
</template>
<script>
export default {
    name: 'Level',
    props:{
        type: String || Number
    }
}
</script>

Level组件根据父组件穿过来的type来判断显示h1、h2、h3等标签,v-if 可以说用到了"极致",而且写了很多个冗余的slot

使用render函数和JSX语法来改写上面

Level.js文件

export default {
    props:{
        type: String | Number
    },
    methods:{
        handleClick(e){
            console.log(e.target)
        },
    },
    data(){
        return {msg:'zf'}
    },
    render(h){ //运行时
        // h('h' + this.type,{},[this.$slots.default])
        let tag = 'h' + this.type
        return <tag>
            <span value={tag} onClick={this.handleClick}>{this.$slots.default}</span>
            {this.msg}
        </tag>
    }
}

省去了很多冗余代码,页面一下清爽了很多

用JSX语法实现v-model、v-if、v-for语法

v-model:

export default {
    methods:{
        handleInput(e){
            this.msg = e.target.value
        }
    },
    data(){
        return {msg:'zf'}
    },
    render(){ //运行时return 
            {/* 实现v-model */}
            <input type="text" value={ this.msg} onInput={this.handleInput}></input>
            {this.msg}
    }
}

给input框顶一个value属性 一个input事件onInput,传值和监听事件改变值。

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:以menu菜单为例

import elMenu from "./el-menu";
import elMenuItem from "./el-menu-item";
import elSubmenu from "./el-submenu";

export default {
    //父组件传过来的数据
    props:{
        data:{
            type: Array,
            default:() => {}
        }
    },
    data(){
        return {
            menudata:[
                {title: '根1', id: 1},
                {title: '根2', id: 2, children: [
                  {
                    title:'根2-1', id: 21,
                    children: [
                      {title: '根2-1-1', id: 211},
                      {title: '根2-1-2', id: 212}
                    ]
                  }
                ]
                },
                {title: '根3', id: 3},
                {title: '根4', id: 4,children: [
                  {title: '根4-1', id: 41}
                ]}
              ]
        }
    },
    render() {
        let renderChildren = (data) => {
            return data.map(child =>{
                return child.children ? //判断是否有孩子
                //有孩子渲染elSubmenu
                <elSubmenu> 
                    <div slot="title">{child.title}</div>
                    {renderChildren(child.renderChildren)}
                </elSubmenu> : //没有孩子渲染elMenuItem
                <elMenuItem></elMenuItem>
            })
        }
        return <elMenu>
            {/* 循环遍历孩子 显示哪一个 */}
            {renderChildren(this.data)}
        </elMenu>
    }
}

 用自定义组件

导入进来,不用再在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

 在实际开发中并不是全部都有renderJSX语法好或者全都用template好,而是在需要的地方两者结合使用,效果会更好。

上一篇:初识react


下一篇:蒲公英 · JELLY技术周刊 Vol.07: EcmaScript 2020 -- 所有你想要知道的都在这