Vue 混合使用模板与jsx

作者: admin 日期: 2020-07-08 18:08:57 人气: - 评论: 0

我们知道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>


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>


原理也很简单,通过创建一个子组件 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>


相关内容

发表评论
更多 网友评论0 条评论)
暂无评论

Copyright © 2012-2014 我的代码板 Inc. 保留所有权利。

页面耗时0.0198秒, 内存占用1.83 MB, 访问数据库12次

闽ICP备15009223号-1