vue中jsx应用

304 阅读1分钟

1.概念

jsx 起源于react,其实就是在js中能够直接编写html标签。最终还是会被渲染生成虚拟dom, 浏览器默认是不支持直接解析,需要借助插件才能实现jsx的解析。 一般需要安装@vue/babel-helper-vue-jsx-merge-props

npm i @vue/babel-helper-vue-jsx-merge-props

2.优势

template只能实现简单逻辑的处理,当遇到复杂的判断与动态输出,则无法胜任。 这时自动写vue的render方法会变得灵活许多,再配合jsx,会让代码标签化更加明显。

例子对比

1.template写法

<tempalte>
    <h1 v-if="level == 1">
        <slot></slot>
    </h1>
    <h2 v-eseif="level == 2">
        <slot></slot>
    </h2>
    <h3 v-eseif="level == 3">
        <slot></slot>
    </h3>
</tempalte>

纯js写法

export default {  
    props: {  
        level: {  
            typeNumber,  
            default1  
        }  
    },  
    renderfunction (createElement) {  
        return createElement(  
            'h' + this.level//标签名称  
            this.$flots.default // 子元素数组  
    }  
}

jsx写法

export default {  
    props: {  
        level: {  
            typeNumber,  
            default1  
        }  
    },  
    renderfunction (h) {  
        const tag = `<h${this.level}>`;  
        return  <tag>{this.$slots.default}<tag/>;  
    }  
}

3.render与createElement

vue中所有组件最终都会通过调用render方法生成vnode,如果定义的是tempalte则会先转化为render。每一个vnode都是通过createElement统一创建,也就是我们常说的h函数


export default {
    name: 'xxx',
    render: function(h) {//在render函数里 createElement会做参数传入
      return (
        <div>
          <div>{this.msg}</div>
          <div>{this.$slots.demo}</div>
          <div>{this.$scopedSlots.data(this.detail)}</div>
        </div>
      );
    },
}

h函数也可以通过全局的获得

 const h = this.$createElement

4.例子

export default {
  props: {
    info: {
      type: Object,
      default() {
        return {name:jason,age:18};
      },
    },
  },
  data() {
    return {
      title: "标题",
    };
  },
  render() { 
    return (
      <div>
        <input type="text" v-model={this.title} />
        <input type="text" v-model={this.info.name} />
        <input type="text" v-model={this.info.age} />
      </div>
    );
  },
};

当定义了render函数 组件就会优先以render创建组件,忽略template的代码。在render里我们可以使用this访问组件上下文的this内容。

5.template 到 jsx代码差异

5.1常用vue指令

#v-bind 
  <input :disabled="true" />
  <input disabled={true} /> 

#v-if
  <span v-if="item == 1">1</span>
  <span v-else>2</span>
  
  {item == 1 ? <span>1</span> : <span>2</span>} 

#v-for
  <ul>
      <li v-for="item in arr" :key={item}>{{item}}</li>
  </ul>
  
  <ul>
      {arr.map(item => <li key={item}>{item}</li>)}
  </ul> 

#v-show
    <h1 v-show:isShow />标题<h1>
   // jsx也支持
    <h1 v-show:isShow />标题<h1>
     
#v-model 
 <h1 v-model:title />标题<h1>
 
 jsx默认不支持 可以使用插件babel-plugin-jsx-v-model 
 

#绑定自定义事件 
  <button @click="myClick">测试</button>
  
  // on-click和onCLick都可以
  <button on-click={myClick}>测试</button>
  <button onClick={myClick}>测试</button>

#绑定原生事件
  <my-component @click.native="testClick" />
  // 驼峰写法 
  <my-component nativeOnClick={testClick} />
 

5.2element-table & 插槽

scopedSlots 是组件默认的插槽属性,可以直接调用访问

 render() {
    return ( <el-table border data={this.rows}>  
          <el-table-column align="center" label="id" width="50" prop="id" /> 
          <el-table-column align="left" label="标题" width="500" prop="view_path" />
          <el-table-column align="left" label="內容" width="200" prop="content" />
          <el-table-column align="left" label="数据1" width="200" prop="data" 
          scopedSlots={{ 
            default: (scoped) => {
              return (<span>{JSON.stringify(scoped.row.data)}</span>)
            }, 
          }} 
           > 
          </el-table-column>  
          {this.renderColData()} 
        </el-table>)
  }
  
  method:{
   renderColData() { 
        return this.$createElement('el-table-column', {
            props: {
              align:"left" ,
              label:"数据2" ,
              width:"200" ,
              prop:"data" ,
            },
            scopedSlots: {
                default: ({ row }) => {
                    return (
                        <span onClick={this.consoleInfo} >{JSON.stringify(row.data)}</span>
                    )
                }
            }
        })
    },
   consoleInfo() { 
       console.log("方法被调用")
   }
  }

6.template与jsx 混编

<template>
  <div>
    <span>Message: {{ msg }}</span>
    <VNodes :vnodes="getSpan()" />
    <VNodes :vnodes="getMyH(2)" />
  </div>
</template>
<script>

export default {
  components: {
    VNodes: { //这里在引入的组件直接定义组件为函数式组件
      functional: true, 
      render: (h, ctx) => ctx.props.vnodes
    }
  },
  data() {
    return {
      msg: "xxxx"
    };
  },
  methods: {
    getSpan() {
      return <span>Message: {this.msg}</span>;
    },
    getMyH(level) {
      const Tag = `h${level}`;
      return <Tag>Hello world!</Tag>;
    }
  }
};
</script>