开开森森学前端之函数式组件和JSX

前言

咱们接着上篇学习完render函数,下面咱们来看下Vue中的函数式组件 这也是Vue进阶中一个重要的知识点,下面咱们一块儿来学习下吧(我也不是很熟😄,有错误就请指正)javascript

组件封装阶段

咱们先封装一个简单的组件,叫作listhtml

代码以下:vue

<template>
  <ul>
    <li v-for="(item, index) in list" :key="`item_${index}`"></li>
  </ul>
</template>
<script>
export default {
  name: 'List',
  props: {
    list: {
      type: Array,
      default: () => []
    }
  }
}
</script>
复制代码

简单封装后,里面li里面的内容咱们先无论!java

咱们再新建一个叫作render的组件 咱们把刚刚的list组件引入到render组件里bash

<template>
  <div>
    <list :list="list"></list>
  </div>
</template>
<script>
import List from '../component/list'
export default {
  data () {
    return {
      list: [
        { name: lili},
        { name: Dreams}
      ]
    }
  },
  components: {
    List
  }
}
</script>
复制代码

接下来,咱们回到list组件里完善下li标签里面的内容dom

<li v-for="(item, index) in list" :key="`item_${index}`">
<span>{{ item.name }}</span>
</li>
复制代码

这样咱们就把刚刚render组件里传递进来的list数据给list组件使用而且渲染出了名字,这里咱们用span标签包裹了,那么若是咱们想更多的让用户个性化,好比用户想用什么标签包裹就用什么标签包裹,怎么作呢?函数

那么这里咱们就可使用render函数,而后让用户经过render函数本身去定义,来看下怎么写学习

这里咱们回到render组件,把render函数经过v-bind传递到list里去字体

render组件的代码:
<template>
  <div>
    <list :list="list" :render="renderFunc"></list>
  </div>
</template>
<script>
import List from '../component/list'
export default {
  data () {
    return {
      list: [
        { name: lili},
        { name: Dreams}
      ]
    }
  },
  components: {
    List
  },
  methods:{
      renderFunc(h){
         return h('i',{
            style:{
                color:'pink'
            }
         },'???') 
      }
  }
}
</script>
复制代码

上面咱们想使用i标签包裹,且字体颜色为粉红色,但这里咱们打问号的地方他的值是多少呢?怎么来呢,由于list中他是经过v-for循环的, 那么咱们想知道当前循环的这个值是多少,那么这里咱们就要用到一个组件叫作:函数式组件ui

函数式组件开始

那么接着上面,咱们先建立一个render-dom.js 代码以下

export default {
  functional: true,//必须这样写才是一个函数式组件
  props: {
    name: String,
    renderFunc: Function
  },
  render: (h, ctx) => {
    //???
  }
}
复制代码

那么有人会问了,函数式组件有什么做用?

通常而言,咱们只给它传入一些数据,它不作任何响应式的操做,不监听传递给他的状态,它也没有生命周期,它只是一个接收参数的函数,当设置functionaltrue时,它是一个没有状态的组件,可是当你把他引入到其余vue组件中去用的时候,vue会把它作相关处理,上面咱们写了一个render函数,vue会用render函数里的逻辑,把里面返回的节点作渲染!

接着咱们回到list组件,在props里接收父组件(render组件)传递过来的render函数

props处新增代码:

render: {
      type: Function,
      default: () => {}
}
复制代码

接下来,咱们把函数式组件再完善下

把刚刚render方法里的逻辑完善下就是

render: (h, ctx) => {
   return ctx.props.renderFunc(h,ctx.props.name)
}
复制代码

返回的render其实就是用户传进来的那个render ctx他其实就指代当前的上下文,那么咱们就能够用ctx获取到属性里的renderFunc

接下来继续到list组件里使用renderDom函数式组件

模板中新增:
<li v-for="(item, index) in list" :key="`item_${index}`"> <span v-if="!render">{{ item.number }}</span> <render-dom v-else :render-func="render" :name="item.name"></render-dom> </li> script引入: import RenderDom from '../component/render-dom' components: { //注册组件 RenderDom }, 复制代码

这里逻辑就是若是用户传入了render,咱们就是用传入的render渲染,不然默认span

接下来咱们回到render组件里把刚刚的render函数完善下:

renderFunc(h,name){
     return h('i',{
        style:{
            color:'pink'
        }
     },name) 
}
复制代码

那么这里的name其实就是函数式组件返回的name,因此这里咱们直接使用name

那么这样咱们就完成了可让用户本身定义这个文字该怎么样展示!render配合函数式组件就是这么灵活!

那么你们应该也发现了,render加函数式组件其实很是繁琐!那么有没有什么东西能够简化呢? 实际上是有的,那就是JSX!

JSX

JSX是React最早提出的,那么后来Vue也作了相关支持!他的本质其实就是在js中写html标签和一些特定的语法,最终呢他会把jsx转换成render函数去渲染。

接下来咱们回到render组件里把刚刚的render函数修改下:

以前template是这样的:
<list :list="list" :render="renderFunc"></list>
以前js是这样的:
renderFunc(h,name){
     return h('i',{
        style:{
            color:'pink'
        }
     },name) 
}
修改以后的template:
<list :list="list" :render="renderFunc" :style="{color:'red'}"></list>
修改以后的js:
renderFunc(h,name){
     return (
        <i style={{color:'red'}}>{name}</i>
     )
}
复制代码

这里要注意了,在jsx中,变量要用花括号包起来!里面是一个对象,而后又有一个花括号.由于name也是变量,因此也须要使用花括号包起来!

这样就完成了和刚刚render函数同样的功能!

若是咱们想给i标签绑定一个事件,咱们应该怎么绑定?

methods:{
    renderFunc(h,name){
     return (
        <i on-click={this.handleClick} style={{color:'red'}}>{name}</i>
     )
    },
    handleClick(event){
        console.log(event)
    }
}
复制代码

这里还要注意,绑定事件必须是on-开头

那么普通的渲染标签咱们会了,那么若是渲染一个组件呢?

渲染组件

那么这里假设咱们这里有一个组件CountTo(看过上上篇文章的小伙伴应该知道)组件

咱们把他引入到render组件(看过上篇文章的小伙伴应该知道这个组件)中.再写一遍!

咱们这里须要修改以前的一些代码:

render组件中修改后的:(函数式组件和list里须要作一部分修改,我相信你们能够的,就不罗列相关代码了)

<template>
  <div>
    <list :list="list" :style="{color: 'red'}"></list>
  </div>
</template>
<script>
import List from '_c/list'
import CountTo from '_c/count-to'
export default {
  data () {
    return {
      list: [
        { number: 100 },
        { number: 45 }
      ]
    }
  },
  components: {
    List
  },
  methods: {
    renderFunc (h, number) {
      return (
        <CountTo nativeOn-click={this.handleClick} on-on-animation-end={this.handleEnd} endVal={number} style={{color: 'pink'}}></CountTo>
      )
    },
    handleClick (event) {
      // console.log(event)
    },
    handleEnd () {
      // console.log('end!')
    }
  }
}
</script>
复制代码

咱们若是是在render或者jsx里写的组件是不须要进行注册的!

那么这里咱们也使用了JSX作了相同的事情。其实这里还可使用做用域插槽作一样的事情,这篇文章咱们主要讲JSX和函数式组件,因此就再也不举插槽相关的代码哦,有兴趣的能够下去本身试试!

总结

本篇文章咱们一块儿学习了render+函数式组件,最终咱们完成了以前的需求,但过程仍是比较繁琐的,结尾咱们也提到了JSX的解决方案, 感兴趣的小伙伴能够关注我,你们一块儿学习vue中比较难理解的知识点哦!

各位大佬,若是发现文中的错误,请指正,我会及时修改!

感谢大佬们能在百忙中能阅读完这篇文章!

再次总结

相信你们看完这篇文章后再去看vue文档就不会以为那么吃力了!你们共勉!

相关文章
相关标签/搜索