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渲染出来!