jQuery 和 vue 等混用时点击等 dom 事件会失效,这是因为 vue 是虚拟 dom,在初始化、数据变化时会重新渲染,此时原有事件会全部丢失,导致 jquery 绑定的事件不是最终的 dom。
比如以下示例代码:
<!-- 示例代码 -->
<script src="//unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<button id="test">测试</button>
</div>
<script>
const t1 = document.getElementById('test')
const t2 = document.getElementById('test')
console.log(t1 === t2) //true
new Vue({
el: '#app',
mounted() {
const t3 = document.getElementById('test')
console.log(t3 === t2) //false
},
})
</script>
在 script 脚本刚执行的时候,读取 2 次#test,他们是相同的一个,而 vue 初始化完成以后再次获取#test,此时相比较就已经不是同一个了。由此也可以发现,即便他们的 ID 相同,也并非相同的 DOM,在 Vue 初始化之前绑定的事件自然也就会失效。
推荐把 jQuery 的代码改写成 Vue 的事件绑定,也比较利于后续维护,但如果由于某些原因确实需要 jQuery 的代码和 Vue 的代码混用,有以下几种方式,请根据实际情况选择:
1.把需要 jQuery 操作的 DOM 移动到 Vue 作用域之外
这种办法需要修改 DOM 结构,适合弹层提示等相对独立的场景,比如我们刚才的示例代码有一段是 el:"#app"
,id 是 app 的 dom 就是 Vue 的作用域,把需要 jQuery 操作的 DOM 移动到#app 外层,就不会受到 Vue 的影响。但采用此方法的时候,要注意 CSS 或其他操作是否依赖 DOM 结构。
2.在 Vue 渲染完成再执行事件监听
这也是网上教程比较常见的做法,不需要修改 DOM 结构,对代码的修改也相对较少。比如对整体的 jQuery 添加一个延迟,也可以放到 ready 函数中再监听代码,如以下示例代码。
$(document).ready(function () {
$(function () {
// 在这里开始写事件监听
})
})
3.借助事件委托
事件委托是利用事件冒泡,只指定一个事件处理程序来管理某一类型的所有事件。具体原理、实现情况可以上网查阅,我这里只写一个修改示例,不需要修改 DOM 结构,对代码只需要针对性调整。
// 改写之前,这样在Vue中不能使用
$('#test').on('click', function (event) {})
// 改写成这样,这样在Vue中能使用
$('body').on('click', '#test', function (event) {})