理解vue中render函数

首先要理解如何通过props来进行父子组件之间传值,参考https://segmentfault.com/a/1190000010913794。更多详情查看官网:cn.vuejs.org/v2/guide/re…

父组件

<template>
  <div>
    <component :my-data="items" :is="currentView"></component>
  </div>
</template>

<script>
import child from './child'
export default {
  data () {
    return {
      items: [1, 2, 3, 4],
      currentView: child
    }
  }
}
</script>
复制代码

一.基本用法

子组件 child.js

export default {
  props: {
    myData: Array
  },
  render: function (createElement) {
    return createElement('h3', this.myData)
  }
}
复制代码

注: 第一个标签参数为必填项

<figure>[图片上传中...(image-e4a43d-1543413213894-8)]

<figcaption></figcaption>

</figure>

二.添加样式、方法

子组件 child.js

export default {
  props: {
    myData: Array
  },
  return createElement('h3', {
      'class': {
        foo: true,
        bar: false
      },
      style: {
        color: 'red',
        fontSize: '18px'
      },
      attrs: {
        id: 'my-data'
      },
      on: {
        click: this.handleClick
      }
      domProps: {
        innerHTML: this.myData
      }
  }),
  methods: {
    handleClick: function() {
        console.log(' I am data! ');
    }
  }
}
复制代码

<figure>[图片上传中...(image-c4c402-1543413213894-7)]

<figcaption></figcaption>

</figure>

或者也可以把内容放在外面

export default {
  props: {
    myData: Array
  },
  return createElement('h3', {
      'class': {
        foo: true,
        bar: false
      },
      style: {
        color: 'red',
        fontSize: '18px'
      }
  },this.myData)
}
复制代码

<figure>[图片上传中...(image-558bec-1543413213894-6)]

<figcaption></figcaption>

</figure>

三.数组循环输出

子组件 child.js

export default {
  let items = this.myData
  return createElement('div',
    Array.apply(null, { length: items.length }).map(function (item, index) {
        return createElement('h3', items[index])
    })
  )
}
复制代码

<figure>[图片上传中...(image-6638b8-1543413213894-5)]

<figcaption></figcaption>

</figure>

四.添加子元素

子组件 child.js

export default {
  return createElement('div', [// 由createElement函数构建而成的数组
    createElement('h1', '主标'), // createElement函数返回VNode对象
    createElement('h2', '副标')
  ])
}
复制代码

<figure>[图片上传中...(image-b689f0-1543413213894-4)]

<figcaption></figcaption>

</figure>

五. this.$slots用法

父组件

<template>
  <div>
    <component :my-data="items" :is="currentView">
      <h1 slot="header"><span>About Me</span></h1>
      <p>Here is some page content</p>
      <p slot="footer">Copyright 2016 Evan You</p>
      <p>If I have some content down here</p>
    </component>
  </div>
</template>

<script>
import child from './child'
export default {
  data () {
    return {
      items: [1, 2, 3, 4],
      currentView: child
    }
  }
}
</script>
复制代码

子组件 child.js

export default {
  const {header, footer} = this.$slots
  const body = this.$slots.default
  return createElement('div', [
    createElement('header', header),
    createElement('main', body),
    createElement('footer', footer)
  ])
}
复制代码

<figure>[图片上传中...(image-b34d3f-1543413213893-3)]

<figcaption></figcaption>

</figure>

六. v-model用法

父组件

<template>
  <div>
    <component :name="name" :is="currentView" @input="val=>name=val"></component>
    <div>你的名字是:{{name}}</div>
  </div>
</template>

<script>
import child from './child'
export default {
  data () {
    return {
      name: '',
      currentView: child
    }
  }
}
</script>
复制代码

子组件 child.js

export default {
  props: {
    name: String
  },
  render: function (createElement) {
    var self = this
    return createElement('input', {
      domProps: {
        value: this.name
      },
      on: {
        input: function (event) {
          self.$emit('input', event.target.value)
        }
      }
    })
  }
}
复制代码

<figure>[图片上传中...(image-77eb3f-1543413213893-2)]

<figcaption></figcaption>

</figure>

七.作用域插槽(获取子组件数据)

父组件

<template>
  <div>
    <child>
      <template scope="props">
        <span>{{props.text}}</span>
      </template>
    </child>
  </div>
</template>

<script>
import child from './child'
</script>
复制代码

子组件 child.js

export default {
  props: {
    name: String
  },
  render: function (createElement) {
    return createElement('div', [
      this.$scopedSlots.default({
        text: 'hello world!'
      })
    ])
  },
}
复制代码

<figure>[图片上传中...(image-4298da-1543413213892-1)]

<figcaption></figcaption>

</figure>

八. 子组件之间传递作用域插槽

父组件

<template>
  <div>
    <child></child>
  </div>
</template>

<script>
import child from './child'
</script>
复制代码

子组件 child.js

import Vue from 'vue'
export default {
  render: function (createElement) {
    return createElement('div', [
      createElement('children', {
        scopedSlots: {
          default: function (props) {
            return [
              createElement('span', '来自父组件'),
              createElement('span', props.text)
            ]
          }
        }
      })
    ])
  }
}
Vue.component('children', {
  render: function (createElement) {
    return createElement('b',
    this.$scopedSlots.default({
      text: '我是子组件'
    }))
  }
})
复制代码

<figure>[图片上传中...(image-aef571-1543413213892-0)]

<figcaption></figcaption>

</figure>

九. 函数化组件

父组件

<template>
  <div>
    <child :data="data"></child>
  </div>
</template>

<script>
import child from './child'
export default {
  data () {
    return {
      data: {}
    }
  },
  components: {child},
  methods: {
    change: function (type) {
      if (type === 'img') {
        this.data = {
          type: 'img',
          url: 'https://raw.githubusercontent.com/iview/iview/master/assets/logo.png'
        }
      } else if (type === 'video') {
        this.data = {
          type: 'video',
          url: 'http://vjs.zencdn.net/v/oceans.mp4'
        }
      } else if (type === 'text') {
        this.data = {
          type: 'text',
          content: '这是一段纯文本'
        }
      }
    }
  },
  mounted: function () {
    this.change('img')
  }
}
</script>
复制代码

子组件 child.js

// 图片组件
var ImgItem = {
  props: ['data'],
  render: function (createElement) {
    return createElement('div', [
      createElement('p', '图片组件'),
      createElement('img', {
        attrs: {
          src: this.data.url
        }
      })
    ])
  }
}
// 视频组件
var VideoItem = {
  props: ['data'],
  render: function (createElement) {
    return createElement('div', [
      createElement('p', '视频组件'),
      createElement('video', {
        attrs: {
          src: this.data.url,
          controls: 'controls',
          autoplay: 'autoplay'
        }
      })
    ])
  }
}
// 纯文本组件 
var TextItem = {
  props: ['data'],
  render: function (createElement) {
    return createElement('div', [
      createElement('p', '纯文本组件'),
      createElement('p', this.data.text)
    ])
  }
}
export default {
  functional: true,
  render: function (createElement, context) {
    function getComponent () {
      var data = context.props.data
      switch (data.type) {
        case 'img':
          return ImgItem
        case 'video':
          return VideoItem
        default:
          return TextItem
      }
    }
    return createElement(
      getComponent(),
      context.data
      // context.children
    )
  }
  //在 2.3.0 或以上的版本中,你可以省略 props选项,所有组件上的特性都会被自动解析为 props。
  // props:{
  //    data:Object
  //}, 
}
复制代码

注: 在添加 functional: true 之后,锚点标题组件的 render 函数之间简单更新增加 context 参数,this.$slots.default 更新为 context.children,之后this.data 更新为 context.props.data

组件需要的一切都是通过上下文传递,包括:

  • props:提供所有 prop 的对象
  • children: VNode 子节点的数组
  • slots: 返回所有插槽的对象的函数
  • data:传递给组件的数据对象,作为 createElement 的第二个参数传入组件
  • parent:对父组件的引用
  • listeners: (2.3.0+) 一个包含了所有在父组件上注册的事件侦听器的对象。这只是一个指向 data.on 的别名。
  • injections: (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性。

作者:十二柚不檬
链接:https://juejin.im/post/5bfcf70f51882512e76c64fb
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值