如何将 Vue VNode 渲染为字符串
Posted
技术标签:
【中文标题】如何将 Vue VNode 渲染为字符串【英文标题】:How to render a Vue VNode to a String 【发布时间】:2021-01-20 04:09:23 【问题描述】:我正在尝试在我的 Vue 组件中使用 CSS 掩码。我需要完成下面toSvg
函数的实现。这会将来自 this.$slots.default
的 Vue VNode 渲染为 SVG 字符串。
<script>
export default
computed:
maskImage()
const svg = this.toSvg(this.$slots.default);
const encodedSvg = btoa(svg);
return `url('data:image/svg+xml;base64,$encodedSvg')`;
,
,
methods:
toSvg(vnode)
// TODO: How can I convert the VNode to a string like the one below?
// In React, I could use const svg = ReactDOMServer.renderToStaticMarkup(vnode);
return `<svg viewBox="0 0 260 68" xmlns="http://www.w3.org/2000/svg">
<rect x="80" y="32" rx="2" />
<rect rx="2" />
<rect x="80" y="52" rx="2" />
<rect y="26" rx="2" />
</svg>`;
,
,
render(createElement)
return createElement("div",
attrs:
class: "skeleton",
style: `-webkit-mask-image: $this.maskImage; mask-image: $this.maskImage;`,
,
);
,
;
</script>
<style lang="scss">
.skeleton
animation: skeleton-animation 2s infinite linear;
background: linear-gradient(to right, hsl(30, 1, 99) 0%, hsl(30, 2, 95) 30%, hsl(30, 2, 95) 70%, hsl(30, 1, 99) 100%) 0 0 / 200% 100% hsl(30, 2, 95);
overflow: hidden;
position: relative;
width: 200px;
height: 100px;
@keyframes skeleton-animation
100%
background-position: -200% 0;
</style>
使用示例:
<u-skeleton>
<svg viewBox="0 0 260 68" xmlns="http://www.w3.org/2000/svg">
<rect x="80" y="32" rx="2" />
<rect rx="2" />
<rect x="80" y="52" rx="2" />
<rect y="26" rx="2" />
</svg>
</u-skeleton>
显示为:
【问题讨论】:
【参考方案1】:使用Vue.extend
构造一个SVG组件构造函数,在构造函数的render function
内部,渲染slots.default
。
下一步是创建它的实例,然后mount()
并获取编译后的 html。
Vue.component('v-test',
computed:
maskImage()
let vnodes = this.$slots.default
let SVGConstructor = Vue.extend(
render: function (h, context)
return h('svg',
attrs:
xmlns: 'http://www.w3.org/2000/svg'
, vnodes)
)
let instance = new SVGConstructor()
instance.$mount()
const encodedSvg = btoa(instance.$el.outerHTML);
return `url('data:image/svg+xml;base64,$encodedSvg')`;
,
render(createElement)
return createElement("div",
attrs:
class: "skeleton",
style: `-webkit-mask-image: $this.maskImage; mask-image: $this.maskImage;`,
,
)
,
)
new Vue(
el: '#app'
)
.skeleton
animation: skeleton-animation 2s infinite linear;
background: linear-gradient(to right, #fcfcfc 0%, #f3f2f2 30%, #f3f2f2 70%, #fcfcfc 100%) 0 0 / 200% 100% #f3f2f2;
overflow: hidden;
position: relative;
width: 200px;
height: 100px;
@keyframes skeleton-animation
100%
background-position: -200% 0;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<v-test>
<svg viewBox="0 0 260 68" xmlns="http://www.w3.org/2000/svg">
<rect x="80" y="32" rx="2" />
<rect rx="2" />
<rect x="80" y="52" rx="2" />
<rect y="26" rx="2" />
</svg>
</v-test>
<hr>
<v-test>
<svg viewBox="0 0 260 68" x="0" y="0" xmlns="http://www.w3.org/2000/svg">
<rect x="80" y="32" rx="2" />
<rect rx="2" />
<rect x="80" y="52" rx="2" />
<rect y="26" rx="2" />
</svg>
<svg viewBox="0 0 260 68" x="20" y="-20" xmlns="http://www.w3.org/2000/svg">
<rect x="80" y="32" rx="2" />
<rect rx="2" />
<rect x="80" y="52" rx="2" />
<rect y="26" rx="2" />
</svg>
</v-test>
</div>
【讨论】:
以上是关于如何将 Vue VNode 渲染为字符串的主要内容,如果未能解决你的问题,请参考以下文章