vue中使用jsx或render

1,566 阅读3分钟
让你明明白白学知识,有代码,有讲解,抄的走,学的会!

一、vue 中使用jsx 写组件

直接上代码

<script>
export default {
  name: 'breadcrum',
  props: {
    breadcrumbList: {
      type: Array,
      defalut: () => []
    }
  },
  data() {
    return {
      row: {
        id: '',
        text: ''
      }
    }
  },
  render () {
    console.log(this.breadcrumbList)
    return (
      <div>
        {
          this.breadcrumbList.map((p, index) => {
            if (index === this.breadcrumbList.length - 1) {
              return <span>{p.text}</span>
            } else {
              return <span onclick={() => this.getCurrentIndex(p)}>{p.text}></span>
            }
          })
        }
        <p class='current'>当前点击了--> {this.row.text}</p>
      </div>
    )
  },
  methods: {
    getCurrentIndex (item) {
      console.log(item)
      this.row = item
    }
  }
}
</script>

<style lang='scss' scoped>
.current {
  margin: 10px 0;
  margin-left: 30px;
  color: red;
}
</style>

在父组件中使用上面的 breadcrumb 组件, 在使用 jxs编写的组件 传参和注册组件的方式,没有任何区别

<template>
	<div>
    	<breadcrumbbreadcrumbList='breadcrumbList'></breadcrumb>
    </div>
</template>
import breadcrumb from './components/breadcrumb'
export default {
	components: {
    	breadcrumb
    },
    data() {
    	return {
        	breadcrumbList: [
            	{id: 1, text: '一级标签'},
                {id: 2, text: '二级标签'},
                {id: 3, text: '三级标签'}
            ]
        }
    }
}

效果图

上面能这样写,是因为有 babel 插件 将我们的 vue中的 jsx 转换成 render 渲染函数

注意事项

在 vue中使用 jsx 语法,如果熟悉 react语法的人,去看这个,基本还OK,vue中的 jxs 比 react多了的就是

  • 上下文this的绑定
  • react中写 class是 className ,vue中绑定class 还是class
  • jxs 中是没有 for 这个东西的,如果要遍历 列表,使用 map
  • 事件绑定,就行内事件的绑定方式 onclick, onchange, onmounsedown, onmouseleave 等
  • 使用jsx 再没有那些简单的语法糖方法, 比如 v-model.lazy @keyup.enter等等,要实现,就自己用原生写

二、使用 render 方法写组件

现在我们使用vue 本身提供的 render 方法,写一个简单的内容,在不掺杂成熟的组件库的情况下,看看过程有多痛苦

原生HTML 结构, 非vue 我想表达的HTML结构如下

<div class='bg-red'>
	<button>倒置</button>
    <button>添加</button>
    <div>
    	<div>1</div>
        <div>2</div>
        <div>3</div>
        .......
    </div>
</div>

好,开始 render 函数,硬刚

renderCom.vue 组件

<script>
export default {
  name: 'renderComponent',
  data () {
    return {
      arr: [1, 2, 3, 4, 5]
    }
  },
  render (h) {
    let arr = this.arr
    
    return h('div', {
      class: 'bg-red',
      title: '我是一个属性',
      style: {
        border: "1px solid red"
      },
      // 增加自定义属性
      attrs: {
        age: 12
      }
    }, [
      // 数组增加多个子节点
      h('button', {
      	// 绑定事件
        on: {
        // 箭头函数是为了 获取到 data中的内容,否则上面要定义一个 self = this
          click: () => {
            // 获取data中的数据,并倒置
            this.arr = this.arr.reverse()
          }
        }
      }, '倒置'),
      h('button', {
        on: {
          click: () => {
            this.arr.push(this.arr.length + 1)
          }
        }
      }, '添加')
      , h('div', {
        style: {
          // 复合样式,大写
          marginTop: '50px'
        }
        // 没有for循环,循环使用 map 然后 返回 虚拟节点 h('div')
      }, arr.map(p => h('div', {
        style: {
          height: '32px',
          borderBottom: '1px dashed #fefefe',
          // 还有这种,引号,横线写法,类 css
          'padding-left': '40px'
        }
      }, p)))])
  }
}
</script>

<style scoped>
.bg-red {
  background: red;
}
</style>

render函数输出组件-效果图

乍一看,我嘞个去,这是啥, 太恶心了吧, 代码行数 55行

废话不多说,直接进入重点

注意事项

  • 事件的绑定, on ,render写法 没有模板的语法糖了, v-model.lazy 之类的,想要类似效果,纯原生js,自己刚
  • 样式绑定和 纯原生js的是差不多的
  • 事件绑定,需要注意使用 data中的内容,请使用 箭头函数, 否则 this指向不对;
  • 子元素(子组件), 使用 [] 继续编写 render函数,仍旧返回 虚拟DOM
  • 遍历节点, template写法有语法糖 v-for , render写法, map 自己使用 h() 仍旧返回虚拟DOM
  • 自定义属性,写在 attrs中, jquery时代,特别喜欢挂载自定义属性,进行传参, 那在render中,就都放在 attrs中

反正恶心的写法你也见到了,还不去写 template写法,写业务,template写法,在可维护上,代码的简洁程度高了一大截,这是毋庸置疑的, 但是有人就是说,我就要 render或者 jxs 的灵活, 用法没有绝对的好坏, “好刀用在钢刃上”, 你说是吧

三、番外篇

使用 render 函数返回组件的内容,就没有 vue是不会再从 template 中或者指定的el中提取模板了

这里我们从 Vue 的生命周期图可以知道,如果有template 就会将template中的内容编译到 render中, 所以,render 函数的目的就是 返回虚拟DOM

render --》 template --》 el

<template>
	<div>一些内容</div>
</template>

export default {
	el: '这里可以指定一个模版'render() {
    	return (
        	<div>以这个内容为主要</div>
        )
    }
}

上面这个,在UI层展示的内容,只有 render 返回的, template中的直接被丢弃