前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue的v-html指令使用注意事项

vue的v-html指令使用注意事项

作者头像
挥刀北上
修改2019-07-19 16:05:17
21.9K0
修改2019-07-19 16:05:17
举报
文章被收录于专栏:Node.js开发Node.js开发

今天说一下Vue开发时使用V-html时候碰到的一些问题,首先我们要明白什么时候使用v-html,当需要渲染的数据包含html片段的时候,比如下面的内容:

但是这里有几点需要开发者注意:

1、V-html更新的是元素的 innerHTML 。内容按普通 HTML 插入, 不会作为 Vue 模板进行编译 。

但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件,代码如下:

代码语言:javascript
复制
<body>
  <div id="app">
    <p>hello world</p>
    <my-html></my-html>
  </div>
  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    Vue.component("my-html", {
      data() {
        return {
          content: `<div>23231213{}<div>`,
          title: "title"
        }
      },
      template: `<div v-html="content"></div>`
    })
    new Vue({
      el: "#app"
    })
</script>
</body>

渲染效果如下:

遇到这种情况,我们该如何处理呢?这里官方文档给了解决方案:

如果试图使用 v-html 组合模板,可以重新考虑是否通过使用组件来替代。

修改代码如下:

代码语言:javascript
复制
<body>
  <div id="app">
    <p>hello world</p>
    <my-html></my-html>
  </div>
  <script src="./lib/vue-2.4.0.js"></script>
  <script>
    Vue.component("my-html", {
      data() {
        return {
          content: "",
          title: "title"
        }
      },
      template: `<div>
                <div id='parent'>这里本来使用v-html,但是不能解析插值表达式</div>
                <h1>{}</h1>
                </div>`,
      mounted() {
        // 将组件数据拷贝,
        // 用一个组件实例来渲染html格式字符串生成dom
        // dom操作将生成的dom插入页面
        let obj = Object.assign({}, this.$data);
        let component = Vue.extend({
          template: `<div >我是要渲染的html格式字符串{}</div>`,
          data() {
            return obj
          }
        })
        let dom = new component().$mount().$el;
        document.querySelector("#parent").appendChild(dom)
      }
    })
    new Vue({
      el: "#app"
    })
</script>
</body>

仔细观察,在父组件的mounted生命周期函数内,我们通过生成一个组件实例的形式将html格式字符串渲染成了一个dom元素,最终通过dom操作将其插入页面。以上代码可以优化,我们将html格式字符串转换为dom的操作封装为一个函数,代码如下:

代码语言:javascript
复制
<body>
<div id="app">
    <p>hello world</p>
    <my-html></my-html>
</div>
<script src="./lib/vue-2.4.0.js"></script>
<script>
    // 将html格式字符串转化为dom的函数
    function htmlStrToDom(htmlstr, parentdata) {
        let obj = Object.assign({}, parentdata);
        let component = Vue.extend({
            template: htmlstr,
            data() {
                return obj
            }
        })
        let instance = new component().$mount();
        return instance.$el
    }
    Vue.component("my-html", {
        data() {
            return {
                content: "",
                title: "title"
            }
        },
        template: `<div>
                    <div id='parent'>这里本来使用v-html,但是不能解析插值表达式</div>
                    <h1>{}</h1>
                </div>`,
        mounted() {
            let dom = htmlStrToDom(`<div>我是要渲染的html格式字符串{}</div>`, this.$data)
            document.querySelector("#parent").appendChild(dom)
        }
    })
    new Vue({
        el: "#app"
    })
</script>
</body>

仔细观察上面的代码,我们发现我们进行了dom操作,而在使用vue框架是,是要尽量避免dom操作的,所以我们拿到要渲染的html格式的字符串时,我们可以将生成的dom转化为innerHTML,然后还是通过v-html将其绑定到要渲染的位置,代码如下:

代码语言:javascript
复制
<script>
    // 将html格式字符串转化为dom的函数
    function htmlStrToDom(htmlstr, parentdata) {
        let obj = Object.assign({}, parentdata);
        let component = Vue.extend({
            template: htmlstr,
            data() {
                return obj
            }
        })
        let instance = new component().$mount();
        return instance.$el
    }
    Vue.component("my-html", {
        data() {
            return {
                content: "",
                title: "哈哈哈哈哈",
                
            }
        },
        template: `<div>
                    <div id='parent' v-html="content">这里本来使用v-html,但是不能解析插值表达式</div>
                    <h1>{}</h1>
                </div>`,
        mounted() {
            // 通过innerHTML特性将其转化为html格式字符串;
            let html = htmlStrToDom(`<div>我是要渲染的html格式字符串<h1>{}</h1></div>`, this.$data).innerHTML;
            // 修改content值,观察组件中要渲染html格式字符串的位置,我们还是用v-html来绑定
            this.content = html;
        }
    })
    new Vue({
        el: "#app"
    })
</script>

以上这种做法相对来说比较容易理解,就是在将html格式的字符串真正渲染前,我们使用一个组件实例将其渲染处理一下,将其内部的插值表达式、模板处理完之后,在渲染。

使用v-html需要注意的第二个问题是:在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 <style>元素手动设置类似 BEM 的作用域策略。

以上是Vue官网的提供的注意事项,本质就是scoped的样式对V-html内部的元素不会生效,该怎么办?

第一种解决方案,照样使用scoped,但是我们可以使用深度选择器(>>>),示例如下:

代码语言:javascript
复制
<style scoped>.a >>> .b{/* ... */}</style>

以上代码最终会被编译为:

代码语言:javascript
复制
.a[data-v-f3f3eg9] .b{/* ... */}

但是这里需要注意,当你的vue项目使用less或者sass的时候,>>>这个玩意可能会失效,我们用/deep/来代替,代码如下:

代码语言:javascript
复制
.a {
/deep/ .b{/* ... */}
}

第二种解决方案,单文件组件的style标签可以使用多次,可以一个stlye标签带scoped属性针对当前组件,另外一个style标签针对全局生效,但是内部我们采用特殊的命名规则即可,例如BEM规则。

以上便是在使用vue开发时使用v-html需要注意的地方。

引用资料:

https://blog.csdn.net/qq_31393401/article/details/81017912 https://www.jianshu.com/p/27dd92bbd206 https://wolfx.cn/vue-scoped-css-questions/ https://www.jianshu.com/p/50c043bce9e1 https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-20,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 nodejs全栈开发 微信公众号,前往查看

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

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com