Foreword
Many backend management systems use a large number of images. In order to optimize the problem of repeated uploads, most of them will first upload an image for repeated use. Use the ID of the material to select the reference. Today I will share a simple small component that I made. How to build this component step by step. Because everyone has differences in practice, I will focus on the ideas and finally attach the source code (pulled from my project, so the interface and other things vary from person to person). , it cannot be used directly by copying it, it can be used after subtraction)
Technology stack: vue3 combined api + Element-Plus (vue3 version of elemetUI)
Interface: Adding, deleting, and modifying resource categories, uploading, modifying, and deleting resources
Page structure analysis
Normal page
<!-- Use direct page routing --> <div> <el-card shadow="hover" :body-style="{ padding: '20px' }"> <chooseResource></chooseResource> </el-card> </div>
First-level structure
the whole frame
This component is divided into a picture selector parent component and a classification sub-component. The reason why classification is separated into a sub-component is to facilitate the operation of adding and deleting categories on another page (deleting top-level nodes is not allowed in the picture selector)
This can be divided into two sides of the structure
<el-row :gutter="20"> <!-- Category on the left --> <el-col v-bind="grid"> <!-- Classification subcomponent --> </el-col> <!-- Image operations on the right --> <el-col v-bind="grid2"> <!-- Detailed operation of the picture on the right --> </el-col> </el-row>
Secondary structure
The classification group on the left is an example of the official website. It is very simple with the custom editing menu at the end.
Three-layer structure on the right: first layer operation menu; middle layer: picture display; not fixed height; use flex layout; flex-wrap to change lines
Next level paging
Each picture consists of el-image, input box and modification icon
Pop-up window structure
<!-- Select the pop-up window method --> <div> <el-dialog title="Select image" v-model="resourceVisible" show-close close="setResourceVisible(false)" width="70%"> <chooseResource v-if="resourceVisible" :visible="resourceVisible" :choose_type="choose_type" @chooseSingle="changeSingle" @chooseList="changeList" /> <template #footer> <span> <el-button @click="setResourceVisible(false)">Cancel</el-button> </span> </template> </el-dialog> </div>
Roughly the same as the normal page structure, except that the operation menu determines whether selection is being made based on the incoming choose_type to display the “Select Image” button.
Practical operation
Category subcomponent
The classification subcomponent on the left uses simple addition, deletion, modification and search
<el-tree ref="treeRef" :data="dataSource" node-key="value" :filter-node-method="filterNode" default-expand-all :expand-on-click-node="false" :highlight-current="true" > <template #default="{ node, data }"> <div class="custom-tree-node" @click.stop="handleNodeClick(data)" > <div> <span>{<!-- -->{ node.label }}</span> </div> <div class="flexRowAlign" v-if="data.value" style="font-size:1.2rem"> <!-- Add --> <el-icon ><Plus /></el-icon> <!-- Modify --> <el-icon><EditPen /></el-icon> <!-- Delete --> <el-icon><Delete /></el-icon> </div> </div> </template> </el-tree>
<script setup lang="ts"> //Throw out the category ID for image upload and modification management const handleNodeClick=(data)=>{ console.log('Select category',data) emit('selectCG',data.value) } </script>
The Add component and Update component in the source code both assist in adding and modifying categories. You can change the interface on the outer layer and modify the displayed and submitted data on the inner layer.
Picture selection parent component
Parameters passed in
Choose mode: choose_type
single single selection picture
list multiple selection pictures
Callback
@chooseSingle: Select a single picture and return the id and url of the picture
@chooseList: Returns the image id array and url array
Select image operation
- v-for generates a picture list imgList, and uses isSelect in the item to determine whether it is selected. Each time a picture is selected, it is saved in the array. If it is already selected and selected again, it will be deselected and removed from the array.
//Select the picture const imgIDList=ref([]) const imgSrcList=ref([]) const imgInfoList=ref([]) const chooseImg=(item)=>{ if(!item.isSelect){//Determine whether multiple selections can be made by choose_type if(imgIDList.value.length==1 & amp; & amp;props.choose_type=='single'){ ElMessage.warning('Only one picture can be selected') return } item.isSelect = true; imgIDList.value.push(item.resource_id) imgSrcList.value.push(item.resource_url) imgInfoList.value.push(item) }else{ item.isSelect = false; const index=imgIDList.value.indexOf(item.resource_id)//Get the index if(index==-1)return imgIDList.value.splice(index,1) imgSrcList.value.splice(index,1) imgInfoList.value.splice(index,1) } console.log('picture list',imgIDList.value,imgSrcList.value) // chosenImgList.value.push(row.resource_id) }
Change name operation
Since each picture is separate, editId is needed to record the operation of changing the name. Use the item’s id and editId to determine whether to display the input modification box.
<!-- Picture list --> <div class="list flexRow"> <template v-if="imgList.length!=0"> <div class="list_item flexCol" v-for="(item,index) of imgList" :key="index"> <el-image class="list_img" :src="item.resource_url" @click.stop="chooseImg(item)" :class="item.isSelect?'list_img_choose':''" /> <!-- Input box --> <div class="flexRowAlign"> <el-input v-model="editName" v-if="editId === item.resource_id"></el-input> <div class="itemName flexRowCenter" style="width: 80%;" v-else>{<!-- -->{item.resource_title}}</div> <!-- Modify --> <el-icon class="mx-1 hoverLight" @click.stop="changeName(item)"><EditPen /></el-icon> </div> </div> </template> <template v-else> <span>There are no pictures in this category</span> </template> </div>
const editId=ref(0) const editName=ref('') const changeName=(data)=>{ console.log('modified data',data) if(editId.value==data.resource_id){ if(data.resource_title!=editName.value){ if(!editName){ ElMessage.warning('Please enter the picture name first') return } let obj=Object.assign({},data) obj.resource_title=editName.value updateResourceApi(obj).then(res=>{ if(res.code==200){ ElMessage.success('Modification successful') } data.resource_title=editName.value }).catch(err=>{ ElMessage.error(err.message) }).finally(()=>{//Reset the selected id editId.value=0 editName.value='' }) }else{//Cancel modification editId.value=0 editName.value='' } }else{//Select the modified picture editId.value=data.resource_id editName.value=data.resource_title } }
When using pictures, emit triggers the callback and returns the data.
//Use pictures const emit=defineEmits(['chooseSingle','chooseList']) const usePhoto=()=>{ if(props.choose_type=='single'){ emit('chooseSingle',imgIDList.value[0],imgSrcList.value[0]) }else if(props.choose_type=='list'){ emit('chooseList',imgIDList.value,imgSrcList.value) } }
Other operations
For uploading, deleting, and moving, just connect to your own interface. For moving and deleting, use an array loop to connect to the interface.
More
You can optimize loading speed by selecting images by loading thumbnails, as well as various style optimizations.
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Vue entry skill treevue3 basics (JS)Vue3 component communication 39441 people are learning the system