此系列旨在记录实习中遇到的技术问题,方便日后再次遇到可以查阅。
最近在做实习以来的第二个需求,在一个由后端数据动态生成的表单中添加上传文件、下载文件和更新文件的按钮。
上传文件的功能本来我就没自己写过,问ai才知道应该用按钮配合点击事件来触发被隐藏的input组件的click事件,来实现按钮与文件上传组件的联动。OK听起来不难,写写看。
然后不出意外,写的依托勾石,完全跑不通...
仔细复盘了一下,发现应该是ref与v-for一起使用的问题。首先声明一点,这两者可以一起使用,但是,不能像我之前这么用...
我最开始的代码belike:
<template>
<div v-for="(item,index) in 10" :key="index">
<input type="file" :ref="ITEM"/>
<button @click="func()">click</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const ITEM = ref(null)
const func = () => {
ITEM.value.click()
}
</script>
bro以为input的ref会分身😅,第一版有点蠢的没边了,改!
第二版稍微像个正常人写的了:
<template>
<div v-for="(item,index) in 10" :key="index">
<input type="file" :ref="ITEMs[index]"/>
<button @click="func(index)">click</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const ITEMs = ref(new Array(10).fill(null))
const func = (index) => {
ITEMs.value[index].click()
}
</script>
看起来已经无懈可击了,对吧!
对吗???
那这时候豆包就告诉我:亲,ref不支持这么写哦~要使用高阶函数哟!
于是我又查了查什么叫高阶函数...
总算可以跑了,最后一版如下:
<template>
<div v-for="(item,index) in 10" :key="index">
<input type="file" :ref="setRef(index)"/>
<button @click="func(index)">click</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const ITEMs = ref(new Array(10).fill(null))
const setRef = (index) => (el) => {
ITEMs.value[index] = el
}
const func = (index) => {
console.log(ITEMs.value[index])
ITEMs.value[index].click()
}
</script>
那么长话短说呢,就是在获取input实例的时候,使用一个函数来实现,也就是setRef,它的返回值也是个函数(所谓高阶函数),返回的函数接受一个参数el,代表input实例,被赋值到用于存储实例的数组中index下标对应的位置。
源自搜索:在 Vue 中, ref 指令可以接收一个函数作为值。当组件挂载时,这个函数会被调用,并且将对应的 DOM 元素或者组件实例作为参数传入;当组件卸载时,这个函数同样会被调用,不过此时传入的参数为 null 。
不过呢,当时一直出问题,搞得我有点急,所以实际代码中没有使用ref的方案,而是使用label配合input来实现绑定文件选择框到按钮(当然也是豆包教我的🤫)总之是可以跑通的~