本文介绍: 通过官方文档可以得知两个重点:① 通过vhtml生成页面元素,不会被当做Vue模板进行编译,只会作为普通的html代码插入,也就是通过vhtml插入html@clickvif等,则不会生效,因为他们没有被Vue编译,而浏览器并不会识别这些vue语法,所以这些语法都不生效。② 在.vue文件中如果style标签上增加了scoped属性,那么该标签内的样式就不会对vhtml生成的页面元素作用还是因为这些元素没有被当做Vue模板进行编译,所以不生效。

一、简介

官方文档

在这里插入图片描述
通过上面官方文档介绍我们可以得知两个重点

通过v-html生成的页面元素,不会被当做Vue模板进行编译,只会作为普通的html代码插入,也就是通过v-html插入的html代码中,如果包含vue语法例如@clickv-if等,则不会生效,因为他们没有被Vue编译,而浏览器并不会识别这些vue语法,所以这些语法都不生效。

② 在.vue文件中如果style标签上增加了scoped属性,那么该标签内的样式就不会对v-html生成的页面元素作用,还是因为这些元素没有被当做Vue模板进行编译,所以不生效。

如果在某些业务场景我们v-html生成的页面元素绑定@click事件需要触发某些处理方法,或者需要给这些元素设置CSS样式时,这两个问题比较致命了,所以我们要想办法去解决这俩问题

解决绑定事件失效方法有:使用onclick原生事件代替@click等事件vue事件、利用事件委托触发事件、使用component模板代替v-html

解决样式不生效的方法有:/deep/::v-deep>>>:deep额外全局<style>

二、解决@clickvue事件不触发

1、使用onclick原生事件代替@clickvue事件

思路 vue事件之所以不能被触发是因为,v-html生成的页面元素,是在Vue文件编译之后插入到页面中的,不会被Vue编译,只会作为普通的html代码被插入,所以无法识别vue事件。既然是普通的html代码,那我们可以使用原生的事件去代替vue事件,原生事件一定会被触发,但此时又出现一个问题,那就是原生事件被触发后,无法访问到vue实例data中的数据methods中的方法,究其原因还是由于没有被vue编译的问题。
既然问题出现了,那就想办法解决问题。既然访问不到vue实例中的数据方法,那么我们可以将事件所需要使用的数据和方法,挂载window对象上,这样就可以原生事件访问到了。

具体代码
<template&gt;
  <div class="hello"&gt;
  	<!-- 渲染文本数据 --&gt;
    <div class="box" v-html="html"&gt;
    </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进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注