v-html的问题及解决办法

1、v-html和v-text(简写:{{}})相比,可以识别字符串中的标签

  data() {
    return { html1: '<p>HTML1</p>' }
  }
    <p v-html="html1"></p>
    <p v-text="html1"></p>
    <p>{{html1}}</p>

  结果:

    

2、v-html会覆盖当前标签内的子元素

    <div v-html="html1">
      <h1>标题</h1>
    </div>

  结果:

    

3、样式问题

  scoped的样式不会应用在v-html内部,因为v-html的内容没有经过vue的模板编译器处理

  解决办法:

    ①使用scoped时用深度选择器(>>>),scss和less使用 /deep/

  data() {
    return { html1: '<p class="my-p">HTML1</p>' }
  }
    <div v-html="html1"></div>
<style lang="less" scoped>
#app {
  /deep/ .my-p {
    color: red;
  }
}
</style>

    ②不使用scoped,另写一个style标签针对全局样式,这里要使用BEM命名规则

<style lang='less'>
#app {
  .my-p {
    font-size: 30px;
  }
}
</style>

4、XSS

  data() {
    return {
      test: `<a onclick="alert('攻击你')">连接</a>`,
      message: `hello vue<img src="xx" onerror="alert('这里也可以攻击你')">`
    }
  }
    <div v-html="test"></div>
    <div v-html="message"></div>

当图片加载错误时:

点击【连接】时:

如何解决:

  ①安装xss插件:npm i xss

  ②main.js中引入

  import xss from 'xss'
  Vue.prototype.xss = xss

  ③vue.config.js

  chainWebpack: (config) => {
    config.module
      .rule('vue')
      .use('vue-loader')
      .loader('vue-loader')
      .tap((options) => {
        options.compilerOptions.directives = {
          html(node, directiveMeta) {
            ;(node.props || (node.props = [])).push({
              name: 'innerHTML',
              value: `xss(_s(${directiveMeta.value}))`
            })
          }
        }
        return options
      })
  },

  ④重启后这些事件就没了

  ⑤vue官网强调了永远不要让用户输入的内容通过v-html渲染出来!

    

原文地址:https://www.cnblogs.com/wuqilang/p/15161080.html