【问题标题】:How to render a Vue VNode to a String如何将 Vue VNode 渲染为字符串
【发布时间】: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" width="160" height="12" rx="2" />
          <rect width="180" height="20" rx="2" />
          <rect x="80" y="52" width="95" height="12" rx="2" />
          <rect y="26" width="68" height="42" 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" width="160" height="12" rx="2" />
    <rect width="180" height="20" rx="2" />
    <rect x="80" y="52" width="95" height="12" rx="2" />
    <rect y="26" width="68" height="42" rx="2" />
  </svg>
</u-skeleton>

显示为:

【问题讨论】:

    标签: css vue.js svg vue-component css-mask


    【解决方案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" width="160" height="12" rx="2" />
          <rect width="180" height="20" rx="2" />
          <rect x="80" y="52" width="95" height="12" rx="2" />
          <rect y="26" width="68" height="42" 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" width="160" height="12" rx="2" />
          <rect width="180" height="20" rx="2" />
          <rect x="80" y="52" width="95" height="12" rx="2" />
          <rect y="26" width="68" height="42" 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" width="160" height="12" rx="2" />
          <rect width="180" height="20" rx="2" />
          <rect x="80" y="52" width="95" height="12" rx="2" />
          <rect y="26" width="68" height="42" rx="2" />
        </svg>
      </v-test>
    </div>

    【讨论】:

      猜你喜欢
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-10
      • 2018-08-27
      • 2019-03-26
      • 1970-01-01
      • 2020-03-14
      • 2017-09-11
      相关资源
      最近更新 更多