uni-app 【报Bug】v-for [數據] 在 [數據] 被短時間編輯後不工作, 或v-for 的[數據]watcher 失效
uni-app 【报Bug】v-for [數據] 在 [數據] 被短時間編輯後不工作, 或v-for 的[數據]watcher 失效
| 开发环境 | 版本号 | 项目创建方式 |
|---|---|---|
| Windows | win10 | HBuilderX |
产品分类:uniapp/App
PC开发环境操作系统:Windows
HBuilderX类型:正式
HBuilderX版本号:3.1.13
手机系统:Android
手机系统版本号:Android 7.0
手机厂商:電視盒
手机机型:電視盒
页面类型:vue
打包方式:云端
项目创建方式:HBuilderX
示例代码:
<template>
<view class="content">
<button >null</button>
<button @click="initData">initData + downloadFile</button>
<text>第一次打开app要先下载3段影片,\n可自行更换网络较好的资源,\n看见console.log有3个[save sucess ...]代表下载成功</text>
<button @click="setStor">setStor</button>
<text>3断影片都下载好后,手动把数据写入Storage</text>
<button @click="printFileDict">printFileDict</button>
<text>检查是否3断影片都下载好,并保存好</text>
<text>以及打印出convertData及bug-convertData2处理后的handledPlayData,其实一样</text>
<button @click="convertData">convertData</button>
<text>convertData是正常的动作,作用是把原数据转化成播放的数据</text>
<button @click="convertData2">bug-convertData2</button>
<text>convertData2是出现bug的动作,其实跟1动作一样,\n但就在整理数据时,直接在this.handledPlayData上插入数据,\n1就是先用tmpDict先把数据缓取,待制作好后,\n再用this.handledPlayData = tmpDict更换数据</text>
<button @click="cleanData">cleanData</button>
<text>convertData转成convertData2时用</text>
<view>
<view v-for="(value,FrameKey,index) in handledPlayData">
<!-- <text>
{{value.win[0]}} , {{value.win[1]}} , {{value.win[2]}} , {{value.win[3]}}
FrameKey:{{FrameKey}} playIndex:{{value.playIndex}} index:{{index}}
</text> -->
<!-- 以上用于把影片排列可视化 -->
<video :src="getMyMedia(FrameKey)" class='myVideo' autoplay controls=false loop show-loading=false
@ended="playEnd(FrameKey)" :style='
"top:"+value.win[0]+"rpx;"+
"left:"+value.win[1]+"rpx;"+
"width:"+value.win[2]+"rpx;"+
"height:"+value.win[3]+"rpx;"'></video>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
fileDict: {},
oriPlayData: {},
handledPlayData: {}
}
},
onLoad() {
this.getStor()
},
watch: {},
methods: {
cleanData(){
this.handledPlayData = {}
},
initData() {
this.setOriData() //初始化原数据(播放的config)
let that = this
let i
let sampleVideo = [
"https://assets.mixkit.co/videos/preview/mixkit-huge-trees-in-a-large-green-forest-5040-large.mp4", //可以更改为网络下载较快的资源,但setOriData()的Content也要作相对更改
"https://assets.mixkit.co/videos/preview/mixkit-forest-stream-in-the-sunlight-529-large.mp4",
"https://assets.mixkit.co/videos/preview/mixkit-stars-in-space-1610-large.mp4"
]
for (i in sampleVideo) {
// console.log(sampleVideo[i])
uni.downloadFile({
url: sampleVideo[i],
success: (res) => {
console.log('dl sucess')
let tempFilePath = res.tempFilePath;
console.log(res.tempFilePath)
uni.saveFile({
tempFilePath: tempFilePath,
success: (saveRes) => {
let savedFilePath = saveRes.savedFilePath
console.log('save sucess', savedFilePath)
that.fileDict[res.tempFilePath.split('/')[3]] = savedFilePath
}
})
}
})
}
},
setOriData() { //初始化原数据(播放的config)
let oriData = {
"L": "1920",
"W": "1080",
"horizontal": true,
"Frame1": [0, 0, 800, 800],
"Content1": ["mixkit-stars-in-space-1610-large.mp4"],
"Frame2": [0, 800, 800, 800],
"Content2": ["mixkit-stars-in-space-1610-large.mp4", "mixkit-huge-trees-in-a-large-green-forest-5040-large.mp4"],
"Frame3": [800, 0, 800, 800],
"Content3": ["mixkit-stars-in-space-1610-large.mp4", "mixkit-forest-stream-in-the-sunlight-529-large.mp4", "mixkit-huge-trees-in-a-large-green-forest-5040-large.mp4"],
"Frame4": [800, 800, 800, 800],
"Content4": ["mixkit-huge-trees-in-a-large-green-forest-5040-large.mp4"]
}
uni.setStorageSync('oriPlayData', oriData)
},
setStor() {
uni.setStorageSync('File_UniSavedName', this.fileDict)
this.getStor()
},
getStor() {
this.fileDict = uni.getStorageSync('File_UniSavedName')
console.log('fileDict:', this.fileDict)
this.oriPlayData = uni.getStorageSync('oriPlayData')
console.log('oriPlayData:', this.oriPlayData)
},
printFileDict() {
console.log(this.fileDict)
console.log('handledPlayData:',this.handledPlayData)
},
getUniappSaveName(OriMediaName) {
return this.MedList[OriMediaName]
},
convertData() {
console.log(this.handledPlayData)
let that = this
let tmp
let tmpPlayingDict = {}
for (tmp in this.oriPlayData) {
if (tmp.slice(0, 7) == "Content") {
let tmpNum = tmp.split("Content")[1]
let newDictFrame = 'Frame' + tmpNum
tmpPlayingDict[newDictFrame] = {}
tmpPlayingDict[newDictFrame]['win'] = this.oriPlayData[newDictFrame]
tmpPlayingDict[newDictFrame]['Content'] = []
let oriNameMed
for (oriNameMed in this.oriPlayData['Content' + tmpNum]) {
tmpPlayingDict[newDictFrame]['Content'].push(this.fileDict[this.oriPlayData['Content' + tmpNum][oriNameMed]])
}
tmpPlayingDict[newDictFrame]['playIndex'] = 0
}
}
this.handledPlayData = tmpPlayingDict
console.log(this.handledPlayData)
},
convertData2() {
let that = this
let tmp
for (tmp in this.oriPlayData) {
if (tmp.slice(0, 7) == "Content") {
let tmpNum = tmp.split("Content")[1]
let newDictFrame = 'Frame' + tmpNum
console.log(newDictFrame)
this.handledPlayData[newDictFrame] = {}
this.handledPlayData[newDictFrame]['win'] = this.oriPlayData[newDictFrame]
this.handledPlayData[newDictFrame]['Content'] = []
let oriNameMed
for (oriNameMed in this.oriPlayData['Content' + tmpNum]) {
console.log(this.fileDict[this.oriPlayData['Content' + tmpNum][oriNameMed]])
this.handledPlayData[newDictFrame]['Content'].push(this.fileDict[this.oriPlayData['Content' + tmpNum][oriNameMed]])
}
this.handledPlayData[newDictFrame]['playIndex'] = 0
}
}
console.log(this.handledPlayData)
},
playEnd(FrameKey) {
this.handledPlayData[FrameKey].playIndex += 1
// console.log('ended', FrameKey, this.handledPlayData[FrameKey].playIndex)
this.handledPlayData[FrameKey].playIndex = (this.handledPlayData[FrameKey].playIndex) % (this.handledPlayData[FrameKey].Content.length)
},
getMyMedia(FrameKey) {
// console.log('get')
let med = this.handledPlayData[FrameKey].Content[this.handledPlayData[FrameKey].playIndex]
return med
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: right;
}
.myVideo {
position: absolute;
}
</style>
操作步骤:
- 直接按
bug-convertData2按钮
预期结果:
v-for可用,- 影片可以正常播放
实际结果:
v-for不可用- 影片不播放
bug描述:
- 用
v-for [数据], - 当
[数据]被编辑时, - 有可能会导致
v-for不作用 - 我猜应该是
v-for的 watcher 在观察数据是否有变化时, - 因为短时间内
[数据]被频繁编辑,而出现的bug - 由于很难解释,就把代码都贴上了
- 先
[initData + downloadFile]等3断影片下载完成后再按[setStor] - 之后就可以按
[convertData2]不出现预期结果
更多关于uni-app 【报Bug】v-for [數據] 在 [數據] 被短時間編輯後不工作, 或v-for 的[數據]watcher 失效的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于uni-app 【报Bug】v-for [數據] 在 [數據] 被短時間編輯後不工作, 或v-for 的[數據]watcher 失效的实战教程也可以访问 https://www.itying.com/category-93-b0.html
这个问题是由于Vue响应式系统的限制导致的。在convertData2方法中,你直接对this.handledPlayData进行动态属性赋值:
this.handledPlayData[newDictFrame] = {}
Vue无法检测到对象属性的添加或删除,因此这种赋值方式不会触发视图更新。虽然数据确实被修改了,但v-for的watcher没有收到变化通知,导致界面不重新渲染。
相比之下,convertData方法工作正常是因为它先构建完整的tmpPlayingDict对象,然后一次性赋值给this.handledPlayData:
this.handledPlayData = tmpPlayingDict
这种整体替换能够被Vue检测到,从而触发视图更新。
解决方案:
使用$set方法确保属性添加是响应式的:
convertData2() {
let that = this
let tmp
for (tmp in this.oriPlayData) {
if (tmp.slice(0, 7) == "Content") {
let tmpNum = tmp.split("Content")[1]
let newDictFrame = 'Frame' + tmpNum
console.log(newDictFrame)
// 使用$set确保响应式
this.$set(this.handledPlayData, newDictFrame, {
win: this.oriPlayData[newDictFrame],
Content: [],
playIndex: 0
})
let oriNameMed
for (oriNameMed in this.oriPlayData['Content' + tmpNum]) {
console.log(this.fileDict[this.oriPlayData['Content' + tmpNum][oriNameMed]])
this.handledPlayData[newDictFrame].Content.push(this.fileDict[this.oriPlayData['Content' + tmpNum][oriNameMed]])
}
}
}
console.log(this.handledPlayData)
}

