前言
近期在 Vue2
开发中发现 v-for
渲染组件时出现 script
执行一次,且多个组件共享一个 script
作用域。
我现在有这样的界面,统计不同班级的图表数据,正常逻辑肯定是把Card抽出来做成组件
于是得到一个 PieCard.vue
组件,引入 echarts
并实例化饼图
因为 echarts
实例对象不需要在 DOM
中使用,也没必要让 Vue
对其做响应式处理,所以我把实例myChart放到了 script
下的顶级作用域
// PieCard.vue
<template>
<div class="pie-simple-chart-container" title="">
// 省略
<div class="echarts-pie-simple-box" />
</div>
</template>
<script>
import * as echarts from 'echarts'
// echarst 实例
let myChart = null
export default {
mounted () {
this.initEcharts()
},
methods: {
initEcharts () {
const chartContainer = this.$el.querySelector('.echarts-pie-simple-box')
myChart = echarts.init(chartContainer)
myChart.setOption({ ... })
},
},
}
</script>
在父组件中使用 v-for
循环渲染 PieCard.vue
// 父组件
<template>
<div class="card-list-container">
<PieCard v-for="item in cardList" :key="item.id" class="card" :/>
</div>
</template>
到目前目前为止似乎合乎常理没有问题。
继续 为了不让出现内存泄露,咱们在 PieCard.vue
组件 beforeDestroy
生命周期中销毁 echarts
实例对象
// PieCard.vue
<script>
import * as echarts from 'echarts'
// echarst 实例
let myChart = null
export default {
beforeDestroy () {
myChart.dispose() // 销毁实例
},
}
</script>
em... 逻辑上似乎没有问题,但是问题就突然跳出来给了我一耳光。
并跟我说 实例已经被销毁了,不能再次销毁
什么鬼?
我们在 beforeDestroy
打印一下实例到底怎么了
// PieCard.vue
<script>
import * as echarts from 'echarts'
// echarst 实例
let myChart = null
export default {
beforeDestroy () {
console.log(myChart)
},
}
</script>
仔细一看两个实例对象 id
竟然一样?为什么两个子组件的myChart指向一个实例?
难道 script
作用域是同一个?
抱着好奇心 再看看,咱们在 PieCard.vue
的 script
顶级作用域再打印一下
// PieCard.vue
<script>
import * as echarts from 'echarts'
// echarst 实例
let myChart = null
console.log('PieCard script 作用域')
</script>
我两个图表按理说应该打印两次啊,为什么只打一次?
难道是因为 v-for
?
于是我用template-explorer 想看看 v-for
编译后是什么样子
也没看明白,感觉是编译后 引入组件只执行一次,所以 script
也只执行一次,因为 v-for
中是可以访问遍历项的,所以他们应该是共享了一个父级作用域,但是为什么子组件内的 script
作用域为什么是一个,因为没读过源码 不太明白,有大佬懂得的话可以评论区讲一下。
后面试了 v-for
结合 :is
确没有这个问题。
对于我这里这个问题,最终解决方法还是把 echarts
实例对象放到了 data
中