久久r热视频,国产午夜精品一区二区三区视频,亚洲精品自拍偷拍,欧美日韩精品二区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

vue 實(shí)現(xiàn)拖拽動(dòng)態(tài)生成組件的需求

瀏覽:111日期:2022-09-30 11:06:27
產(chǎn)品需求

開(kāi)完產(chǎn)品需求會(huì)議,遇到了一個(gè)需求,首先頁(yè)面分成兩欄布局,左側(cè)展示數(shù)據(jù)組件,支持拖拽排序,點(diǎn)擊按鈕清除組件。右側(cè)支持將組件的縮略圖拖拽至左側(cè)生成一個(gè)新的組件。

思路

對(duì)于動(dòng)態(tài)生成組件來(lái)說(shuō)每一次都要是生成全新的一個(gè)組件,那么就可以把 組件放進(jìn)函數(shù)當(dāng)中 return。在JSX中調(diào)用函數(shù),每次調(diào)用函數(shù)都會(huì)返回一個(gè)全新的組件。這對(duì)React來(lái)說(shuō)非常簡(jiǎn)單,但是對(duì)于Vue來(lái)說(shuō),直接將組件返回是不可能的。盡管這個(gè) return 寫(xiě)法不適合Vue,但是我們不可否認(rèn),思路是非常正確的,所以我們應(yīng)該考慮一個(gè)別的寫(xiě)法。至于動(dòng)態(tài)的生成組件,我們必須以數(shù)據(jù)來(lái)驅(qū)動(dòng)組件的生成。對(duì)于拖拽組件的排序,直接使用拖拽庫(kù)就OK了!!

面臨的問(wèn)題 拖拽庫(kù)的選擇 如何生成組件 以數(shù)據(jù)驅(qū)動(dòng)動(dòng)態(tài)生成組件 拖拽庫(kù)的選擇

拖拽庫(kù)在這里我選擇的是項(xiàng)目中存在的一個(gè)拖拽庫(kù) Vue.Draggable 點(diǎn)這里鏈接查看 Start 14.9K 蠻不錯(cuò)的。如果你們的Vue項(xiàng)目中沒(méi)有用到這個(gè)拖拽庫(kù),你們可以自行參考本片文章的設(shè)計(jì)思路。

如何生成組件

在這里我使用的是 Vue.extend() 不清楚如何使用的小伙伴請(qǐng)?jiān)诠俜轿臋n中查看過(guò)后再來(lái)學(xué)習(xí)這篇文章 Vue.extend 。 接下來(lái)我們創(chuàng)建一個(gè)js文件,用來(lái)書(shū)寫(xiě)創(chuàng)建組件的代碼。

生成組件

/* generateComponents.js 文件名 */import Vue from 'vue';// 想要?jiǎng)討B(tài)生成的組件,先引入這個(gè)文件。import components1 from './components/TestCom1.vue';import components2 from './components/TestCom2.vue';// 將組件的名稱(chēng)和組件做一個(gè)對(duì)應(yīng)Mapconst comMap = { components1, components2,};// 接收生成組件需要的組件名稱(chēng),和想要傳遞給組件的// props, 和 事件const ReturnNewCom = function ({ props, on }) { const { comItem: { name }, } = props; const newComponent = Vue.extend({ render(createElement) { // 使用傳進(jìn)來(lái)的組件name來(lái)決定渲染哪一個(gè)組件。 return createElement(comMap[name], {props,on, }); }, }); return new newComponent();};export default ReturnNewCom;組件

在這里我們書(shū)寫(xiě)兩個(gè)組件,用來(lái)演示這個(gè)Demo,分別為components1.vue,components2.vue。

/*components1.vue*/<template> <div class='widget-wrapper'> <header class='header'>{{ comDetail.name }}--{{ comDetail.id }}</header> <h1>查詢條件:{{ queryObj }}</h1> <button @click='handleDelete'>清除</button> </div></template><script>export default { data() { return { comDetail: this.comItem, _queryObj: this.queryObj, }; }, props: { comItem: { type: Object, default() {return { id: 0, name: '',}; }, }, queryObj: { // 可以接收父組件傳遞的曬選條件,必須是Object type: Object, default() {// 定義默認(rèn)的查詢條件。return { num: 0,}; }, }, }, watch: { comItem(val) { this.comDetail = val; return val; }, queryObj(val) { this._queryObj = val; return val; }, }, created() { console.log('data -> this.comItem', this.comItem); }, methods: { handleDelete() { // 刪除組件方法 this.$el.remove(); // 調(diào)用父組件的函數(shù)。修改父組件中的 leftComList 數(shù)組的數(shù)據(jù)。 this.$emit('handleDelete', this.comDetail); }, },};</script><style scoped>.widget-wrapper { background: #ff7b7b; border-radius: 12px; overflow: hidden; width: 200px;}.header { height: 50px; padding: 0 15px;}</style>

其實(shí)components2.vue文件中的代碼和components1.vue文件的代碼類(lèi)似,唯一不同的地方就是背景顏色不一樣。

以數(shù)據(jù)驅(qū)動(dòng)動(dòng)態(tài)組件的生成

接下來(lái)就得使用Vue.Draggable 這個(gè)拖拽庫(kù)進(jìn)行拖拽和數(shù)據(jù)的修改。 我們可以直接在App.vue文件中直接書(shū)寫(xiě)。

/* App.vue */<template> <div class='dragCom'> <h1>{{ leftComList }}</h1> <button @click='queryObj.num++'>改變查詢條件</button> <div class='body'> <div class='left'><draggable :list='leftComList' :group='’people’'> <div ref='comBody' v-for='({ name, id }, index) in leftComList' :key='id' > <!-- 循環(huán) leftComList 數(shù)組,利用數(shù)據(jù)來(lái)渲染組件, 將動(dòng)態(tài)生成的數(shù)組添加到這個(gè)DOM元素當(dāng)中。 --> {{ handleAddCom({props: { comItem: { name, id }, queryObj },index, }) }} </div></draggable> </div> <div class='right'><draggable :list='rightComList' :group='{ name: ’people’, pull: ’clone’, put: false }' :clone='handleCloneDog'> <div v-for='element in rightComList' :key='element.id'> {{ element.name }} </div> <!-- 右側(cè)的 卡片 數(shù)據(jù), rightComList 數(shù)組對(duì)象中的name就對(duì)應(yīng)了generateComponents.js 中的ComMap中的屬性 --></draggable> </div> </div> </div></template><script>import draggable from 'vuedraggable';import CreateCom from './generateComponents';export default { components: { draggable, }, data() { return { rightComList: [{ id: Math.random(), name: 'components1',},{ id: Math.random(), name: 'components2',}, ], leftComList: [], // 存儲(chǔ)驅(qū)動(dòng)動(dòng)態(tài)生成組件的數(shù)據(jù)。 comMap: new Map(), // 主要的作用就是用來(lái)記錄 // 組件有沒(méi)有渲染到 這個(gè)DOM中, // 如果渲染了就不能再往進(jìn)添加子元素了。 queryObj: {// 主要的作用就是向子組件傳遞查詢條件num: 0, }, }; }, beforeDestroy() { // 清除 記錄 的數(shù)據(jù) this.comMap.clear(); }, methods: { handleAddCom({ index, on = {}, props = { comItem: { name: '', id: 0 } } }) { const {comItem: { id }, } = props; this.$nextTick(() => {// 獲取該節(jié)點(diǎn)的子節(jié)點(diǎn)的長(zhǎng)度const childNodesLength = this.$refs.comBody[index].childNodes.length;// 獲取comBody 這個(gè)DOM 數(shù)組的長(zhǎng)度const comLine = this.$refs.comBody.length;if (!this.comMap.get(id)) { // 如果沒(méi)有渲染過(guò)組件 // 1. 調(diào)用 CreateCom 方法 創(chuàng)建組件。 并傳遞 props 和 事件 const com = CreateCom({ props, on: { handleDelete: this.handleDeleteCom, ...on, }, }); // 2. 生成組件 com.$mount(); if (childNodesLength === 2) { // 如果要添加到兩個(gè)組件中間。那么就將新生成的組件DOM位置進(jìn)行修改放到中間。 // 將最后的組件DOM添加到正確的位置 this.$refs.comBody.splice( index, 0, this.$refs.comBody[comLine - 1] ); } // 3. 將生成的組件添加到改DOM中。 this.$refs.comBody[index].appendChild(com.$el); // 4. 記錄該組件實(shí)現(xiàn)了渲染。 this.comMap.set(id, true);} else { // 該位置的組件已經(jīng)渲染,不需要再次渲染直接返回 return;} }); }, handleDeleteCom({ id }) { // 傳遞給子組件刪除的方法,根據(jù)組件的id來(lái)刪除數(shù)據(jù) const index = this.leftComList.findIndex((item) => item.id === id); if (~index) {// 如果存在這個(gè)id的組件,就刪除this.leftComList.splice(index, 1); } }, handleCloneDog(item) { // 給 leftComList 數(shù)組添加數(shù)據(jù) return {...item,id: Math.random(), }; }, },};</script><style>.dragCom { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}.body { width: 100%; height: 800px; display: flex; justify-content: space-between;}.left { flex: 1; height: 800px; border: 1px solid pink;}.right { width: 20%; height: 800px;}.card { height: 50px; background-color: #40cec7; margin: 12px 0; font-size: 12px; line-height: 50px; cursor: pointer;}.comCard { margin: 12px; display: inline-block;}</style>

這樣就實(shí)現(xiàn)了動(dòng)態(tài)的組件渲染和拖拽排序。

效果

vue 實(shí)現(xiàn)拖拽動(dòng)態(tài)生成組件的需求

源碼

想要嘗試的同學(xué)可以自行下載本文的代碼源碼github

以上就是vue 實(shí)現(xiàn)拖拽動(dòng)態(tài)生成組件的需求的詳細(xì)內(nèi)容,更多關(guān)于vue拖拽動(dòng)態(tài)生成組件的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 双江| 汝南县| 牙克石市| 常德市| 香河县| 龙泉市| 蕉岭县| 美姑县| 阿坝县| 丹寨县| 稻城县| 竹山县| 江山市| 出国| 博白县| 长泰县| 游戏| 仁寿县| 乌拉特后旗| 徐汇区| 仁怀市| 平顶山市| 新源县| 建德市| 新田县| 牙克石市| 邹城市| 萨迦县| 二连浩特市| 定南县| 聊城市| 信宜市| 山丹县| 峨边| 抚宁县| 赞皇县| 清水县| 托克逊县| 长白| 丘北县| 宜阳县|