一、简介
官方文档:
① 通过v-html
生成的页面元素,不会被当做Vue模板进行编译,只会作为普通的html
代码被插入,也就是说通过v-html
插入的html
代码中,如果包含vue的语法,例如:@click
、v-if
等,则不会生效,因为他们没有被Vue编译,而浏览器并不会识别这些vue语法,所以这些语法都不生效。
② 在.vue
文件中如果style
标签上增加了scoped
属性,那么该标签内的样式就不会对v-html
生成的页面元素起作用,还是因为这些元素没有被当做Vue模板进行编译,所以不生效。
如果在某些业务场景下我们给v-html
生成的页面元素绑定了@click
事件,需要触发某些处理方法,或者需要给这些元素设置CSS样式时,这两个问题就比较致命了,所以我们要想办法去解决这俩问题。
解决绑定事件失效方法有:使用onclick
等原生事件代替@click
等事件vue事件、利用事件委托触发事件、使用component
模板代替v-html
。
解决样式不生效的方法有:/deep/
、::v-deep
、>>>
、:deep
、额外的全局<style>
。
二、解决@click等vue事件不触发
1、使用onclick
等原生事件代替@click
等vue事件
思路: vue事件之所以不能被触发是因为,v-html
生成的页面元素,是在Vue文件编译之后插入到页面中的,不会被Vue编译,只会作为普通的html
代码被插入,所以无法识别vue事件。既然是普通的html
代码,那我们可以使用原生的事件去代替vue事件,原生事件一定会被触发,但此时又出现一个新问题,那就是原生事件被触发后,无法访问到vue实例的data
中的数据和methods
中的方法,究其原因还是由于没有被vue编译的问题。
既然问题出现了,那就想办法解决问题。既然访问不到vue实例中的数据和方法,那么我们可以将事件所需要使用的数据和方法,挂载在window
对象上,这样就可以被原生事件访问到了。
具体代码:
<template>
<div class="hello">
<!-- 渲染富文本数据 -->
<div class="box" v-html="html">
</div>
</div>
</template>
<script>
export default {
data() {
return {
// 富文本数据 将原来的@click改为使用onclick
html: '<div>这是v-html渲染的元素 <button οnclick="btnClick()">点击按钮</button></div>',
a: '这是个变量'
}
},
mounted() {
// 将vue实例的方法绑定到window对象中去
window.btnClick = this.btnClick
},
methods: {
btnClick() {
alert('点击事件触发成功 + '+ this.a)
}
}
}
</script>
结论: 这种方法在一定程度上解决了v-html渲染元素不能触发@click的问题,但同样限制条件也比较多,比如:如果通过v-for同时渲染大量相似数据,无法访问当前循环项的数据,也就无法区分不同循环项的数据。所以这种方法只适用于绑定比较简单的事件处理操作。
2、利用事件委托触发事件
思路: 这种方法的原理是将子元素要触发执行的事件绑定到父元素上,点击子元素触发事件将会冒泡到父元素,然后父元素去执行对应的事件处理函数,但是要注意在事件处理函数中通过e.target
去判断,触发事件的元素是不是我们想要绑定的那个元素,只有是目标子元素时,才去执行事件处理逻辑。
具体代码:
<template>
<div class="hello">
<!-- 将事件处理程序绑定到父元素上 利用冒泡原理 -->
<div class="box" v-html="html" @click="btnClick($event)">
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
// 富文本数据 目标子元素为button按钮
html: '<div>这是通过v-html渲染的元素 <button id="btn">点击按钮</button></div>',
a: '这是个变量'
}
},
methods: {
btnClick(e) {
// 判断当前触发事件的元素 是不是目标子元素
if(e.target.id === 'btn')
alert('点击按钮事件触发成功 + '+ this.a)
}
}
}
</script>
调用结果:
结论: 这种方法比较好,不需要对富文本数据进行修改,也不需要修改window对象,比较推荐。
3、使用component模板代替v-html
思路: 前面我们已经得知@click等vue时间之所以不起作用,是因为v-html渲染的数据是在不会被当做Vue模板进行编译,只会作为普通的html
代码被插入,那我们就想一种可以被当成Vue模板的渲染方式,那就是通过component模板来进行渲染。需要引入vue,通过Vue.extend(options) 基础Vue构造器,创建一个“子类”,然后通过vm.$mount()将实例进行编译,最后通过原生js进行挂载。
具体代码:
<template>
<div class="hello">
<div>
父组件
<!-- 用来渲染html数据的父组件 -->
<div class='parent' id='parent'></div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
export default {
name: 'HelloWorld',
data() {
return {
a: '这是a变量'
}
},
mounted() {
// 使用变量暂存一下this指向的vue实例
var that = this;
// 通过Vue.extend创建子类组件
var MyComponent = Vue.extend({
template: '<div>这是通过v-html渲染的元素 <button @click="add()">点击按钮</button></div>',
methods: {
add() {
// 通过暂存的that获取当前实例的数据和方法
alert('触发了点击事件,并访问当时vue实例的变量a: ' + that.a)
that.btnClick()
}
}
})
// 通过 $mount() 将子类组件进行编译
let component=new MyComponent().$mount()
// 通过原生js进行挂载
document.getElementById('parent').appendChild(component.$el);
},
methods: {
btnClick() {
alert('点击按钮触发当时vue实例成功')
}
}
}
</script>
调用结果:
结论: 这种方法看起来比较高端,确实也比较好用,但是不适用于大量数据的渲染,因为会创建过多的vue子类,占用大量内存。
3、解决样式不生效的问题
请查看:vue 之 CSS进行样式穿透的方法(/deep/、::v-deep、>>> 、:deep、额外的全局<style>)
原文地址:https://blog.csdn.net/weixin_45092437/article/details/126561635
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_38812.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!