Vue JSX 语法
   3 分钟阅读

render 函数之 JSX 应用

  • 一。模板缺陷
  • 二。函数式组件
  • 三。JSX 应用
  • 四。render 方法订制组件
  • 五。scope-slot
  • 六。编写可编辑表格

一。模板组件的缺陷

文件是.vue文件,模板的最大特点是扩展难度大,不易扩展。可能会造成逻辑冗余

<Level :type="1">哈哈</Level>
<Level :type="2">哈哈</Level>
<Level :type="3">哈哈</Level>

Level 组件需要对不同的 type 产生不同的标签

<template>
 <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>
</template>
<script>
export default {
 props: {
  type: {
   type: Number
  }
 }
};
</script>

二。函数式组件

文件是.js文件,函数式组件没有模板,只允许提供 render 函数,可以把复杂的逻辑变得非常简单

当时创建 html 时候还是有点麻烦,所以就有jsx

export default {
 render(h) {
  return h("h" + this.type, {}, this.$slots.default);
 },
 props: {
  type: {
   type: Number
  }
 }
};

三。JSX 应用

使用 jsx 会让代码看起来更加简洁易于读取

export default {
 render(h) {
  const tag = "h" + this.type;
  return <tag>{this.$slots.default}</tag>;
 },
 props: {
  type: {
   type: Number
  }
 }
};

四。render 方法订制组件

编写 List 组件可以根据用户传入的数据自动循环列表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- App.vue -->
<List :data="data"></List>
<script>
import List from "./components/List";
export default {
 data() {
  return { data: ["苹果", "香蕉", "橘子"] };
 },
 components: {
  List
 }
};
</script>

<!-- List组件渲染列表 -->
<template>
 <div class="list">
  <div v-for="(item,index) in data" :key="index">
   <li>{{item}}</li>
  </div>
 </div>
</template>
<script>
export default {
 props: {
  data: Array,
  default: () => []
 }
};
</script>

通过 render 方法来订制组件,在父组件中传入 render 方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
  <div>
    <List :data="data" :render="render"></List>
  </div>
</template>

<script>
import List from "./components/List.vue";
export default {
  data() {
    return {
      data: ["苹果", "香蕉", "橘子"]
    };
  },
  components: {
    List
  },
  methods: {
    //执行这里的render的函数来渲染自定义的
    render(h, name) {
      return <span class="diy-class">{name}</span>;
    }
  }
};
</script>

我们需要 createElement 方法,就会想到可以编写个函数组件,将 createElement 方法传递出来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
  <div>
    <div class="list" v-for="(item,index) in data" :key="index">
      <template v-if="render">
        <!-- 将render方法传到函数组件中,将渲染项传入到组件中,在内部回调这个render方法 -->
        <ListItem :render="render" :item="item"></ListItem>
      </template>
      <h1 v-else>{{item}}</h1>
    </div>
  </div>
</template>

<script>
import ListItem from "./ListItem.vue";

export default {
  props: {
    data: Array,
    render: Function
  },
  components: {
    ListItem
  }
};
</script>

ListItem.vue 调用最外层的 render 方法,将 createElement 和当前项传递出来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<script>
export default {
  props: {
    render: {
      type: Function
    },
    item: {}
  },
  render(h) {
    return this.render(h, this.item);
  }
};
</script>

五。scope-slot

??????????????????????

使用 v-slot 将内部值传即可

1
2
3
4
5
6
7
8
9
<List :arr="arr">
    <template v-slot="{item}">
        {{item}}
    </template>
</List>

<div v-for="(item,key) in arr" :key="key">
    <slot :item="item"></slot>
</div>

六。编写可编辑表格

基于 iview 使用 jsx 扩展成可编辑的表格

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<template>
<div>
  <Table :columns="columns" :data="data"></Table>
</div>
</template>
<script>
import Vue from 'vue';
export default {
  methods:{
    render(h,{column,index,row}){
      let value = row[column.key];
      return <div on-click={(e)=>this.changeIndex(e,index)} >
      {this.index === index?
        <i-input type="text" value={value} on-input={(value)=>{
          this.handleChange(value,column,row)
        }} onOn-enter={()=>this.enter(row,index)}/>:
        <span>{value}</span>
      }
      </div>
    },
    enter(row,index){
      this.data.splice(index,1,row);
      this.index = -1;
    },
    handleChange(value,column,row){
      row[column['key']]= value;
    },
    changeIndex(e,index){
      this.index = index;
      this.$nextTick(()=>{
        e.currentTarget.getElementsByTagName("input")[0].focus()
      })
    }
  },
  data() {
    return {
      index:-1,
      columns: [
        {
          title: 'Name',
          key: 'name',
          render:this.render
        },
        {
          title: 'Age',
          key: 'age',
        },
        {
          title: 'Address',
          key: 'address',
        },
      ],
      data: [
        {
          name: 'John Brown',
          age: 18,
          address: 'New York No. 1 Lake Park',
          date: '2016-10-03',
        },
        {
          name: 'Jim Green',
          age: 24,
          address: 'London No. 1 Lake Park',
          date: '2016-10-01',
        },
        {
          name: 'Joe Black',
          age: 30,
          address: 'Sydney No. 1 Lake Park',
          date: '2016-10-02',
        },
        {
          name: 'Jon Snow',
          age: 26,
          address: 'Ottawa No. 2 Lake Park',
          date: '2016-10-04',
        },
      ],
    };
  },
};
</script>