前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue中的renderless 非渲染组件

Vue中的renderless 非渲染组件

作者头像
用户9914333
发布2022-07-22 14:29:27
9890
发布2022-07-22 14:29:27
举报
文章被收录于专栏:bug收集

面试中遇到的一个问题,什么是 renderless ?

renderless 即非渲染组件开发的思想,请看下文

01

什么是 render 函数

众所周知,在工程中,我们会在.vue文件中定义 <template>、<script>和<style>三种tag,分别盛放组件html、javascript和css。

代码语言:javascript
复制
<template>
<button class="mood">
    {{ state ? 'On' : 'Off' }}
</button>
</template>

<script>
export default {
data: () => ({ state: false })
}
</script>

<style>
  .mood:after {
      color: white;
      background: blue;
  }
</style>

但事实上,最后在生产环境中,我们只使用了一个巨大的JS文件,究其缘由还是得益于webpack的vue loader

vuejs会把template元素提取出来,并进一步编译成一个叫render的函数。(有关render函数可以参考官方文档)

代码语言:javascript
复制
render(h) {
  return h(
    'button',
    {class: 'mood'},
    state ? 'On' : 'Off'
  )
}

render函数最后会被vue优化成VNode(虚节点),具体过程我不再赘述了。不过,这里提供了一个很有趣的思路:编写组件时,我们其实可以不写vue文件,不写template,只需要写render函数。

代码语言:javascript
复制
const button = {
  render(h) {
    return h(
    'button',
          {class: 'mood'},
    state ? 'On' : 'Off'
        )
  },
  data() {
    return {state: false}
  }
}

02

Renderless component 概念

这里引入一个Renderless component的概念,直译的话应该叫非渲染组件

Renderless意思就是组件只提供数据操作,不渲染任何内容

代码语言:javascript
复制
const toggle = {
    render() {
    },
data() {
return { state: true }
    },
    methods: {
        toggle() {
this.state = !this.state
        }
    }
}

new Vue({
    el: '#parent',
    components: { toggle },
    ...
})

toggle就是所谓的Renderless组件了,只有数据和方法,不提供html template。父组件直接将其放入components即可当作一般子组件使用。

03

Renderless 示例

Renderless 组件不渲染,那谁负责渲染工作呢?嗯,就是Slots!父组件通过传递自定义的slots来定制子组件的html template。

代码语言:javascript
复制
<toggle v-slot:default="{on, toggle}">
    <div class="container">
        <button @click="click(toggle)">
            {{on ? 'On' : 'Off'}}
        </button>
    </div>
</toggle>

这里提一下v-slot,它是vue 2.6以后的新语法,用来代替之前的 slot 和 slot-scope;v-slot:default 还可以简写成 #default。Vue3应该不会再保留 slot 和 slot-scope 这种不伦不类的标签了。

希望能让插槽访问到子组件toggle里的数据和方法,以便之后点击button更改状态。子组件暴露作用域插槽也很简单,只要在render函数里返回$scopedSlots对象即可,这里因方便起见使用了默认的default插槽,自己实现的时候也可以重命名为任意插槽。

代码语言:javascript
复制
//toggle.js
const toggle = {
    render() {
return this.$scopedSlots.default({
            on: this.state,
            toggle: this.toggle,
        })
    },
data() {
return { state: true }
    },
    methods: {
        toggle() {
this.state = !this.state
        }
    }
}

最后我们在父组件调用renderless组件:

代码语言:javascript
复制
<template>
  <toggle v-slot="{on, toggle}">
        <div class="container">
        <button @click="click(toggle)">
                        {{on ? 'On' : 'Off'}}
        </button>
        </div>
  </toggle>
</template>

<script>
import toggle from 'toggle';

export default {
components: { toggle },
methods: {
        click(fn) {
            fn()
        },
    },
}
</script>

这样一个简单的renderless开关就实现了。

假如你想自定义组件样式,或是说控制toggle渲染方式,更改也很容易,只需要在插槽里写下自定义代码即可:

代码语言:javascript
复制
<toggle #default="{ on, toggle  }">
    <div class="container">
    <button @click="click(toggle)"
    :style="{background: on ? 'green' : 'red'}">
                {{on ? 'On' : 'Off'}}
    </button>
    </div>
</toggle>

因为toggle的逻辑不变,所以我们不需要更改这个renderless组件。只需稍微改动一下slot,button的背景色就会随着开关一起改变了。

嗯,这就是Renderless组件的效果,功能逻辑和页面渲染分开。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bug收集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 03
  • Renderless 示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档