sunnyxujian's blog sunnyxujian's blog
首页
  • JavaScript
  • CSS
  • HTML和浏览器
  • Vue
  • Vue3
  • React
  • 基础知识
  • webpack
  • rollup
  • vite
  • 其他
  • Nodejs
  • 网络
  • TypeScript
  • 架构设计
  • 性能优化
  • 数据结构和算法
  • JavaScript教程 笔记
  • ES6 教程 笔记
  • TypeScript 从零实现 axios
  • Git学习 笔记
  • 渲染器原理
  • TypeScript 笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网站
  • 资源
  • Vue资源
  • 友情链接
  • 分类
  • 标签
  • 归档
  • 友链
  • 关于
GitHub (opens new window)

xujian

劝君惜取少年时。
首页
  • JavaScript
  • CSS
  • HTML和浏览器
  • Vue
  • Vue3
  • React
  • 基础知识
  • webpack
  • rollup
  • vite
  • 其他
  • Nodejs
  • 网络
  • TypeScript
  • 架构设计
  • 性能优化
  • 数据结构和算法
  • JavaScript教程 笔记
  • ES6 教程 笔记
  • TypeScript 从零实现 axios
  • Git学习 笔记
  • 渲染器原理
  • TypeScript 笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网站
  • 资源
  • Vue资源
  • 友情链接
  • 分类
  • 标签
  • 归档
  • 友链
  • 关于
GitHub (opens new window)
  • Vue

    • Vue中的scoped和scoped穿透
    • Vue项目使用mock数据的几种方式
    • Vue在模板中渲染JSX
  • Vue3

  • React

  • 框架
  • Vue
xujian
2021-05-11

Vue在模板中渲染JSX

我们知道Vue的模板提供了一个简洁风格的DSL来描述响应式界面,而JSX却提供了更强的灵活性和抽象能力。

在项目开发中有的时候会遇到一种需求,我们需要在同一个单文件组件中同时使用 template 和 jsx的能力,Vue框架本身好像并不允许这么干。

通过简单的变通好像可以实现这个特性:

jsx.vue

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

test.vue

<template>
    <div>
        <div>111</div>
        <jsx :jsx="renderFn"></jsx>
        <div>222</div>
    </div>
</template>

<script>
import jsx from '../../components/utils/jsx'
export default {
  name: 'test',
  components: {
    jsx
  },
  data () {
    return {
      count: 0
    }
  },
  methods: {
    onAdd () {
      this.count++
    },
    renderFn (h, context) {
      return <div>
        <div>
          <button onClick={this.onAdd}>add</button>
        </div>
        <div class="num">{this.count}</div>

      </div>
    }
  }
}
</script>

<style scoped>
    .num{
        color: red;
    }
</style>
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

原理也很简单,通过创建一个子组件 jsx.vue ,子组件使用render渲染,而子组件的render函数实际上是通过调用父组件传入的一个渲染函数,从而实现了好像在父组件可以混合template和jsx的能力,不过很快会发现一个问题,父组件如果定义了 scoped样式 ,将无定义渲染函数内部的样式 原因就是,虽然渲染函数是写在父组件的,但是vue却会认为这一部内容属于子组件(事实上好像也是如此)

所以我不得不对子组件的实现进行了hack,最后修改的组件如下:

<script>
import { keys, find } from 'ramda'
import { it } from 'partial-application.macro'
export default {
  props: {
    jsx: {
      type: Function
    }
  },
  render (h, context) {
    let rt = this.jsx(h, context)
    this.$nextTick(() => {
      let ds = rt?.parent?.elm?.dataset
      let vid = ds |> keys |> find(it.indexOf('v-') == 0)
      if (!vid) {
        return
      }
      function r (n) {
        let chs = n.children
        if (!chs) {
          return
        }
        for (let c of chs) {
          let ds = c?.elm?.dataset
          if (ds) {
            ds[vid] = ''
          }
          r(c)
        }
      }

      r(rt)
    })
    return rt
  },
  name: 'jsx'
}
</script>
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
编辑 (opens new window)
#Vue
上次更新: 2022/05/22, 18:34:11
Vue项目使用mock数据的几种方式
初识Proxy,Reflect,WeakMap

← Vue项目使用mock数据的几种方式 初识Proxy,Reflect,WeakMap→

最近更新
01
😍Vue3和React都在用的函数式编程,学起来~
02-03
02
链表
11-24
03
基础类型
11-18
更多文章>
Theme by Vdoing | Copyright © 2020-2023 xujian | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式