欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2021年05月06日 10:29:43   作者:Destiny__  
這篇文章主要介紹了vue 如何實(shí)現(xiàn)拖拽動態(tài)生成組件的需求,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下

產(chǎn)品需求

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

思路

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

面臨的問題

  1. 拖拽庫的選擇
  2. 如何生成組件
  3. 以數(shù)據(jù)驅(qū)動動態(tài)生成組件

拖拽庫的選擇

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

如何生成組件

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

生成組件

/* generateComponents.js 文件名 */

import Vue from "vue";

// 想要動態(tài)生成的組件,先引入這個文件。
import components1 from "./components/TestCom1.vue";
import components2 from "./components/TestCom2.vue";

// 將組件的名稱和組件做一個對應(yīng)Map
const comMap = {
  components1,
  components2,
};

// 接收生成組件需要的組件名稱,和想要傳遞給組件的
// props, 和 事件
const ReturnNewCom = function ({ props, on }) {
  const {
    comItem: { name },
  } = props;
  const newComponent = Vue.extend({
    render(createElement) {
      // 使用傳進(jìn)來的組件name來決定渲染哪一個組件。
      return createElement(comMap[name], {
        props,
        on,
      });
    },
  });
  return new newComponent();
};

export default ReturnNewCom;

組件

在這里我們書寫兩個組件,用來演示這個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文件的代碼類似,唯一不同的地方就是背景顏色不一樣。

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

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

/* App.vue */
<template>
  <div class="dragCom">
    <h1>{{ leftComList }}</h1>
    <button @click="queryObj.num++">改變查詢條件</button>
    <div class="body">
      <div class="left">
        <draggable class="left" :list="leftComList" :group="'people'">
          <div
            ref="comBody"
            v-for="({ name, id }, index) in leftComList"
            :key="id"
            class="comCard"
          >
            <!-- 循環(huán) leftComList 數(shù)組,利用數(shù)據(jù)來渲染組件, 
            將動態(tài)生成的數(shù)組添加到這個DOM元素當(dāng)中。 -->
            {{
              handleAddCom({
                props: { comItem: { name, id }, queryObj },
                index,
              })
            }}
          </div>
        </draggable>
      </div>
      <div class="right">
        <draggable
          class="dragArea"
          :list="rightComList"
          :group="{ name: 'people', pull: 'clone', put: false }"
          :clone="handleCloneDog"
        >
          <div class="card" v-for="element in rightComList" :key="element.id">
            {{ element.name }}
          </div>
          <!-- 右側(cè)的 卡片 數(shù)據(jù), rightComList 數(shù)組對象中的name就對應(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: [], // 存儲驅(qū)動動態(tài)生成組件的數(shù)據(jù)。
      comMap: new Map(), // 主要的作用就是用來記錄 
      // 組件有沒有渲染到 class="comCard" 這個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)的長度
        const childNodesLength = this.$refs.comBody[index].childNodes.length;
        // 獲取comBody 這個DOM 數(shù)組的長度
        const comLine = this.$refs.comBody.length;
        if (!this.comMap.get(id)) {
          // 如果沒有渲染過組件

          // 1. 調(diào)用 CreateCom 方法 創(chuàng)建組件。 并傳遞 props 和 事件
          const com = CreateCom({
            props,
            on: {
              handleDelete: this.handleDeleteCom,
              ...on,
            },
          });
          // 2. 生成組件
          com.$mount();
          if (childNodesLength === 2) {
            // 如果要添加到兩個組件中間。那么就將新生成的組件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來刪除數(shù)據(jù)
      const index = this.leftComList.findIndex((item) => item.id === id);
      if (~index) {
        // 如果存在這個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)了動態(tài)的組件渲染和拖拽排序。

效果

 

源碼

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

以上就是vue 實(shí)現(xiàn)拖拽動態(tài)生成組件的需求的詳細(xì)內(nèi)容,更多關(guān)于vue拖拽動態(tài)生成組件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue.js如何實(shí)現(xiàn)路由懶加載淺析

    Vue.js如何實(shí)現(xiàn)路由懶加載淺析

    Vue是可以自定義指令的,最近學(xué)習(xí)過程中遇見了一個需要懶加載的功能,發(fā)現(xiàn)網(wǎng)上這方面的資料較少,所以下面這篇文章主要給大家介紹了關(guān)于Vue.js如何實(shí)現(xiàn)路由懶加載的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • Vue指令指令大全

    Vue指令指令大全

    本文為大家介紹了VUE中內(nèi)置指令包括:v-text,v-html,v-show,v-if,v-else,v-else-if,v-for,v-on,v-bind,v-model,v-pre,v-cloak,v-once
    2019-02-02
  • vue的圖片需要用require的方式進(jìn)行引入問題

    vue的圖片需要用require的方式進(jìn)行引入問題

    這篇文章主要介紹了vue的圖片需要用require的方式進(jìn)行引入問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • vue 實(shí)現(xiàn)模糊檢索并根據(jù)其他字符的首字母順序排列

    vue 實(shí)現(xiàn)模糊檢索并根據(jù)其他字符的首字母順序排列

    這篇文章主要介紹了vue 實(shí)現(xiàn)模糊檢索,并根據(jù)其他字符的首字母順序排列,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • Vue與React的區(qū)別和優(yōu)勢對比

    Vue與React的區(qū)別和優(yōu)勢對比

    這篇文章主要介紹了Vue與React的區(qū)別和優(yōu)勢對比,幫助大家更好的選擇適合自己的前端框架,迷茫的同學(xué)可以進(jìn)來參考下
    2020-12-12
  • Vue中使用Echarts儀表盤展示實(shí)時數(shù)據(jù)的實(shí)現(xiàn)

    Vue中使用Echarts儀表盤展示實(shí)時數(shù)據(jù)的實(shí)現(xiàn)

    這篇文章主要介紹了Vue中使用Echarts儀表盤展示實(shí)時數(shù)據(jù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 如何使用Vue3+Vite+TS快速搭建一套實(shí)用的腳手架

    如何使用Vue3+Vite+TS快速搭建一套實(shí)用的腳手架

    Vite是一個面向現(xiàn)代瀏覽器的一個更輕、更快的?Web?應(yīng)用開發(fā)工具,下面這篇文章主要給大家介紹了關(guān)于如何使用Vue3+Vite+TS快速搭建一套實(shí)用腳手架的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Vue?Router路由hash模式與history模式詳細(xì)介紹

    Vue?Router路由hash模式與history模式詳細(xì)介紹

    Vue?Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,讓構(gòu)建單頁面應(yīng)用變得易如反掌。路由實(shí)際上就是可以理解為指向,就是我在頁面上點(diǎn)擊一個按鈕需要跳轉(zhuǎn)到對應(yīng)的頁面,這就是路由跳轉(zhuǎn)
    2022-08-08
  • vue.js單文件組件中非父子組件的傳值實(shí)例

    vue.js單文件組件中非父子組件的傳值實(shí)例

    今天小編就為大家分享一篇vue.js單文件組件中非父子組件的傳值實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue移動端如何解決click事件延遲,封裝tap等事件

    vue移動端如何解決click事件延遲,封裝tap等事件

    這篇文章主要介紹了vue移動端如何解決click事件延遲,封裝tap等事件,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論