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

手寫可拖動穿梭框組件CustormTransfer vue實(shí)現(xiàn)示例

 更新時間:2022年11月10日 14:56:18   作者:前端叭叭說  
這篇文章主要為大家介紹了手寫可拖動穿梭框組件CustormTransfer vue實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本文內(nèi)容

需求是實(shí)現(xiàn)類似 el-transfer的組件,右側(cè)框內(nèi)容可以拖動排序;

手寫div樣式 + vuedraggable組件實(shí)現(xiàn)。

最終效果圖

組件html布局

新建一個組件文件 CustormTransfer.vue,穿梭框 html 分為左中右三部分,使用flex布局使其橫向布局,此時代碼如下

<template>
  <div class="custom-transfer-cls">
    <div class="left-side"></div>
    <div class="btn-cls"></div>
    <div class="right-side"></div>
  </div>
</template>
<script>
export default {
  name: 'CustomTransferName',
  components: {},
  props: {},
  data () {
    return { }
  },
  computed: { },
  created () {},
  mounted () { },
  methods: {}
}
</script>
<style lang="less" scoped>
.custom-transfer-cls {
  display: flex;
  justify-content: space-between;
  min-height: 120px;
  .left-side,
  .right-side {}
  .btn-cls { }
}
</style>

此時頁面上看不到組件內(nèi)容。

穿梭框左側(cè)內(nèi)容

左側(cè)內(nèi)容是個列表,列表的每一項是多選框checkbox加文字標(biāo)題,列表最上面是標(biāo)題;所以.left-side的代碼如下:

<div class="left-side">
  <!-- 標(biāo)題 -->
  <h4>{{ titles[0] }}</h4>
  <!-- 列表 -->
  <div v-for="left in leftData" :key="left.key" class="item-cls">
    <el-checkbox :checked="left.checked" @change="leftCheckChange(left)" />
    <span :title="left.label">{{ left.label }}</span>
  </div>
  <!-- 數(shù)據(jù)為空時顯示 -->
  <div v-if="leftData.length === 0" class="empty-text">{{ emptypText }}</div>
</div>

解析:

  • 列表標(biāo)題使用h4標(biāo)簽,titles是組件使用者傳入props的標(biāo)題數(shù)組的第一項;
  • 列表數(shù)據(jù) leftData是組件使用者傳入的數(shù)據(jù)處理之后的,因為我們默認(rèn)el-checkbox不勾選,所以在生命周期mounted時,checked設(shè)為false;
  • el-checkbox觸發(fā)change事件時,執(zhí)行函數(shù)leftCheckChange(left),去改變leftData數(shù)組對應(yīng)項的checked設(shè)為取反;
  • 當(dāng)leftData數(shù)據(jù)為空時,顯示數(shù)據(jù)為空的文本,此文本組件使用者可通過 屬性 emptypText 傳入,默認(rèn)'數(shù)據(jù)為空';
  • 列表的每一項的樣式在 .item-cls 定義,內(nèi)容過長時顯示省略號,在 title 屬性中顯示全部內(nèi)容;
  • 列表整體內(nèi)容多時,顯示滾動條,滾動條樣式重寫;

以上內(nèi)容加上樣式、函數(shù)后如下:

<template>
  <div class="custom-transfer-cls">
    <div class="left-side"></div>
    <div class="btn-cls"></div>
    <div class="right-side"></div>
  </div>
</template>
<script>
export default {
  name: 'CustomTransferName',
  components: {},
  props: {
    allData: {
      type: Array,
      default: () => {
        // 對象數(shù)組需要有l(wèi)abel、key兩個屬性
        return []
      }
    },
    emptypText: {
      type: String,
      default: '數(shù)據(jù)為空'
    },
    titles: {
      type: Array,
      default: () => {
        return ['列表 1', '列表 2']
      }
    }
  },
  data () {
    return {
      leftData: []
    }
  },
  computed: { },
  created () {},
  mounted () {
    // 初始化列表1的數(shù)據(jù)
    this.leftData = this.allData.map(a => {
      a.checked = false
      return a
    })
  },
  methods: {
    // 左邊checkbox的change事件
    leftCheckChange (check) {
      this.leftData = this.leftData.map(l => {
        if (l.key === check.key) {
          l.checked = !l.checked
        }
        return l
      })
    }
  }
}
</script>
<style lang="less" scoped>
.custom-transfer-cls {
  display: flex;
  justify-content: space-between;
  min-height: 120px;
  .left-side {
    height: 240px;
    overflow-y: scroll;
    background-color: white;
    width: 140px;
    border: 1px solid #eee;
    border-radius: 4px;
    h4 {
      /* 列表標(biāo)題在列表滾動時吸附在頂部 */
      position: sticky;
      top: 0px;
      z-index: 9;
      background: white;
      text-align: center;
      font-weight: 400;
      margin-bottom: 16px;
    }
    /* 數(shù)據(jù)為空的樣式 */
    .empty-text {
      text-align: center;
      color: #ccc;
    }
    /* 列表每項的樣式,文字很長時顯示省略號 */
    .item-cls {
      margin-left: 12px;
      margin-right: 12px;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    /* 列表的滾動條樣式重寫 */
    &::-webkit-scrollbar {
      width: 1px;
    }
    &::-webkit-scrollbar-thumb {
      background: #ccc;
    }
    &::-webkit-scrollbar-track {
      background: #ededed;
    }
  }
  .btn-cls { }
}
</style>

穿梭框右側(cè)內(nèi)容

右側(cè)的列表需要具有可拖動排序的功能,我使用的使 vuedraggable組件,所以首先需要先安裝npm install vuedraggable -S, 再引入 import draggable from 'vuedraggable',使用時配合 <transition-group>增加過渡效果;代碼如下:

<div class="right-side">
  <h4>{{ titles[1] }}</h4>
  <draggable v-model="rightData">
    <transition-group>
      <div v-for="(right, index) in rightData" :key="right.key" class="item-cls">
        <el-checkbox :checked="right.checked" @change="rightCheckChange(right)" />
        <span>{{ index + 1 + '.' }}</span>
        <span :title="right.label">{{ right.label }}</span>
      </div>
    </transition-group>
  </draggable>
  <div v-if="rightData.length === 0" class="empty-text">{{ emptypText }}</div>
</div>

解析:

  • 右側(cè)的列表樣式和左側(cè)一樣;
  • 只是多了一個<draggable></draggable>組件的使用

此時整體的代碼如下:

<template>
  <div class="custom-transfer-cls">
    <!-- 左側(cè)列表 -->
    <div class="left-side">
      <h4>{{ titles[0] }}</h4>
      <div v-for="left in leftData" :key="left.key" class="item-cls">
        <el-checkbox :checked="left.checked" @change="leftCheckChange(left)" />
        <span :title="left.label">{{ left.label }}</span>
      </div>
      <div v-if="leftData.length === 0" class="empty-text">{{ emptypText }}</div>
    </div>
    <!-- 向左、向右操作按鈕 -->
    <div class="btn-cls"></div>
    <!-- 右側(cè)列表 -->
    <div class="right-side">
      <h4>{{ titles[1] }}</h4>
      <draggable v-model="rightData">
        <transition-group>
          <div v-for="(right, index) in rightData" :key="right.key" class="item-cls">
            <el-checkbox :checked="right.checked" @change="rightCheckChange(right)" />
            <span>{{ index + 1 + '.' }}</span>
            <span :title="right.label">{{ right.label }}</span>
          </div>
        </transition-group>
      </draggable>
      <div v-if="rightData.length === 0" class="empty-text">{{ emptypText }}</div>
    </div>
  </div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
  name: 'CustomTransferName',
  components: {
    draggable
  },
  props: {
    allData: {
      type: Array,
      default: () => {
        // 對象數(shù)組需要有l(wèi)abel、key兩個屬性
        return []
      }
    },
    checkedData: {
      type: Array,
      default: () => {
        // 對象數(shù)組需要有l(wèi)abel、key兩個屬性
        return []
      }
    },
    emptypText: {
      type: String,
      default: '數(shù)據(jù)為空'
    },
    titles: {
      type: Array,
      default: () => {
        return ['標(biāo)題1', '標(biāo)題2']
      }
    }
  },
  data () {
    return {
      leftData: [],
      rightData: []
    }
  },
  computed: {},
  created () {},
  mounted () {
    // 初始化左側(cè)列表1的數(shù)據(jù)
    this.leftData = this.allData.map(a => {
      a.checked = false
      return a
    })
    // 初始化右側(cè)列表2的數(shù)據(jù)
    this.rightData = this.checkedData.map(a => {
      a.checked = false
      return a
    })
  },
  methods: {
    // 左邊選中
    leftCheckChange (check) {
      this.leftData = this.leftData.map(l => {
        if (l.key === check.key) {
          l.checked = !l.checked
        }
        return l
      })
    },
    // 右邊選中
    rightCheckChange (check) {
      this.rightData = this.rightData.map(l => {
        if (l.key === check.key) {
          l.checked = !l.checked
        }
        return l
      })
    }
  }
}
</script>
<style lang="less" scoped>
.custom-transfer-cls {
  display: flex;
  justify-content: space-between;
  min-height: 120px;
  .left-side,
  .right-side {
    height: 240px;
    overflow-y: scroll;
    background-color: white;
    width: 140px;
    border: 1px solid #eee;
    border-radius: 4px;
    h4 {
      /* 列表標(biāo)題在列表滾動時吸附在頂部 */
      position: sticky;
      top: 0px;
      z-index: 9;
      background: white;
      text-align: center;
      font-weight: 400;
      margin-bottom: 16px;
    }
    /* 數(shù)據(jù)為空的樣式 */
    .empty-text {
      text-align: center;
      color: #ccc;
    }
    /* 列表每項的樣式,文字很長時顯示省略號 */
    .item-cls {
      margin-left: 12px;
      margin-right: 12px;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    /* 列表的滾動條樣式重寫 */
    &::-webkit-scrollbar {
      width: 1px;
    }
    &::-webkit-scrollbar-thumb {
      background: #ccc;
    }
    &::-webkit-scrollbar-track {
      background: #ededed;
    }
  }
}
</style>

穿梭框中間向左、向右按鈕

穿梭框的向左、向右按鈕,使用<el-button icon="el-icon-arrow-right"></el-button>實(shí)現(xiàn),代碼如下:

<div class="btn-cls">
  <el-button
    :disabled="toRightDisable"
    plain
    type="default"
    size="small"
    icon="el-icon-arrow-right"
    @click="toRight"
  />
  <el-button
    :disabled="toLeftDisable"
    class="right-btn"
    plain
    type="default"
    size="small"
    icon="el-icon-arrow-left"
    @click="toLeft"
  />
</div>

解析:

  • 按鈕的禁用disabled邏輯,在computed中定義toRightDisable、toLeftDisable;
  • 按鈕的點(diǎn)擊事件 toRight、toLeft,是對左右兩側(cè)列表數(shù)組的運(yùn)算;

此部分的代碼如下:

<template>
  <div class="custom-transfer-cls">
    <div class="left-side"></div>
    <!-- 向左、向右按鈕開始 -->
    <div class="btn-cls">
      <el-button
        :disabled="toRightDisable"
        plain
        type="default"
        size="small"
        icon="el-icon-arrow-right"
        @click="toRight"
      />
      <el-button
        :disabled="toLeftDisable"
        class="right-btn"
        plain
        type="default"
        size="small"
        icon="el-icon-arrow-left"
        @click="toLeft"
      />
    </div>
    <!-- 向左、向右按鈕結(jié)束 -->
    <div class="right-side"></div>
  </div>
</template>
<script>
export default {
  name: 'CustomTransferName',
  components: { },
  props: {},
  data () {
    return {
      leftData: [],
      rightData: []
    }
  },
  computed: {
    // 向左穿梭按鈕的disabled邏輯
    toLeftDisable () {
      return !this.rightData.some(r => r.checked)
    },
    // 向右穿梭按鈕的disabled邏輯
    toRightDisable () {
      return !this.leftData.some(r => r.checked)
    }
  },
  created () {},
  mounted () { },
  methods: {
    // 數(shù)據(jù)向右穿梭
    toRight () {
      // 左減去,右加上
      const leftUnchecked = this.leftData.filter(l => !l.checked)
      const leftChecked = this.leftData.filter(l => l.checked)
      this.leftData = leftUnchecked
      this.rightData = [].concat(this.rightData, leftChecked).map(r => {
        r.checked = false
        return r
      })
    },
    // 數(shù)據(jù)向左穿梭
    toLeft () {
      // 右減去,左加上
      const rightUnchecked = this.rightData.filter(l => !l.checked)
      const rightChecked = this.rightData.filter(l => l.checked)
      this.rightData = rightUnchecked
      this.leftData = [].concat(this.leftData, rightChecked).map(r => {
        r.checked = false
        return r
      })
    }
  }
}
</script>
<style lang="less" scoped>
.custom-transfer-cls {
  display: flex;
  justify-content: space-between;
  min-height: 120px;
  .btn-cls {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .right-btn {
      margin-left: 0;
      margin-top: 8px;
    }
  }
}
</style>

把排序好的穿梭數(shù)據(jù)傳給父組件

即把rightData: []數(shù)據(jù)通過$emit()傳遞出去,父組件監(jiān)聽dragedData事件之后獲取; 定義函數(shù) transferData(),在拖動完成時的@end事件調(diào)用,在向左向右更新了右側(cè)列表數(shù)據(jù)之后調(diào)用;

代碼如下:

methods: {
  // 傳遞數(shù)據(jù)
  transferData () {
    this.$emit('dragedData', this.rightData)
  }
}

整體代碼

<template>
  <div class="custom-transfer-cls">
    <!-- 左側(cè)列表 -->
    <div class="left-side">
      <h4>{{ titles[0] }}</h4>
      <div v-for="left in leftData" :key="left.key" class="item-cls">
        <el-checkbox :checked="left.checked" @change="leftCheckChange(left)" />
        <span :title="left.label">{{ left.label }}</span>
      </div>
      <div v-if="leftData.length === 0" class="empty-text">{{ emptypText }}</div>
    </div>
    <!-- 向左、向右按鈕開始 -->
    <div class="btn-cls">
      <el-button
        :disabled="toRightDisable"
        plain
        type="default"
        size="small"
        icon="h-icon-angle_right"
        @click="toRight"
      />
      <el-button
        :disabled="toLeftDisable"
        class="right-btn"
        plain
        type="default"
        size="small"
        icon="h-icon-angle_left"
        @click="toLeft"
      />
    </div>
    <!-- 右側(cè)列表 -->
    <div class="right-side">
      <h4>{{ titles[1] }}</h4>
      <draggable v-model="rightData" @end="transferData">
        <transition-group>
          <div v-for="(right, index) in rightData" :key="right.key" class="item-cls">
            <el-checkbox :checked="right.checked" @change="rightCheckChange(right)" />
            <span>{{ index + 1 + '.' }}</span>
            <span :title="right.label">{{ right.label }}</span>
          </div>
        </transition-group>
      </draggable>
      <div v-if="rightData.length === 0" class="empty-text">{{ emptypText }}</div>
    </div>
  </div>
</template>
<script>
// 可拖動組件
import draggable from 'vuedraggable'
export default {
  name: 'CustomTransferName',
  components: {
    draggable
  },
  props: {
    allData: {
      type: Array,
      default: () => {
        // 對象數(shù)組需要有l(wèi)abel、key兩個屬性
        return []
      }
    },
    checkedData: {
      type: Array,
      default: () => {
        // 對象數(shù)組需要有l(wèi)abel、key兩個屬性
        return []
      }
    },
    emptypText: {
      type: String,
      default: '數(shù)據(jù)為空'
    },
    titles: {
      type: Array,
      default: () => {
        return ['標(biāo)題1', '標(biāo)題2']
      }
    }
  },
  data () {
    return {
      leftData: [],
      rightData: []
    }
  },
  computed: {
    // 向左穿梭按鈕的disabled邏輯
    toLeftDisable () {
      return !this.rightData.some(r => r.checked)
    },
    // 向右穿梭按鈕的disabled邏輯
    toRightDisable () {
      return !this.leftData.some(r => r.checked)
    }
  },
  created () {},
  mounted () {
    // 初始化左側(cè)列表1的數(shù)據(jù)
    this.leftData = this.allData.map(a => {
      a.checked = false
      return a
    })
    // 初始化右側(cè)列表2的數(shù)據(jù)
    this.rightData = this.checkedData.map(a => {
      a.checked = false
      return a
    })
  },
  methods: {
    // 傳遞數(shù)據(jù)
    transferData () {
      this.$emit('dragedData', this.rightData)
    },
    // 左邊選中
    leftCheckChange (check) {
      this.leftData = this.leftData.map(l => {
        if (l.key === check.key) {
          l.checked = !l.checked
        }
        return l
      })
    },
    // 右邊選中
    rightCheckChange (check) {
      this.rightData = this.rightData.map(l => {
        if (l.key === check.key) {
          l.checked = !l.checked
        }
        return l
      })
    },
    // 數(shù)據(jù)向右穿梭
    toRight () {
      // 左減去,右加上
      const leftUnchecked = this.leftData.filter(l => !l.checked)
      const leftChecked = this.leftData.filter(l => l.checked)
      this.leftData = leftUnchecked
      this.rightData = [].concat(this.rightData, leftChecked).map(r => {
        r.checked = false
        return r
      })
      // 傳遞數(shù)據(jù)
      this.transferData()
    },
    // 數(shù)據(jù)向左穿梭
    toLeft () {
      // 右減去,左加上
      const rightUnchecked = this.rightData.filter(l => !l.checked)
      const rightChecked = this.rightData.filter(l => l.checked)
      this.rightData = rightUnchecked
      this.leftData = [].concat(this.leftData, rightChecked).map(r => {
        r.checked = false
        return r
      })
      // 傳遞數(shù)據(jù)
      this.transferData()
    }
  }
}
</script>
<style lang="less" scoped>
.custom-transfer-cls {
  display: flex;
  justify-content: space-between;
  min-height: 120px;
  .left-side,
  .right-side {
    height: 240px;
    overflow-y: scroll;
    background-color: white;
    width: 140px;
    border: 1px solid #eee;
    border-radius: 4px;
    /* 標(biāo)題樣式 */
    h4 {
      position: sticky;
      top: 0px;
      z-index: 9;
      background: white;
      text-align: center;
      font-weight: 400;
      margin-bottom: 16px;
    }
    /* 數(shù)據(jù)為空時的樣式 */
    .empty-text {
      text-align: center;
      color: #ccc;
    }
    /* 列表每一項樣式 */
    .item-cls {
      margin-left: 12px;
      margin-right: 12px;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    /* 列表滾動條樣式 */
    &::-webkit-scrollbar {
      width: 1px;
    }
    &::-webkit-scrollbar-thumb {
      background: #ccc;
    }
    &::-webkit-scrollbar-track {
      background: #ededed;
    }
  }
  /* 按鈕樣式 */
  .btn-cls {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .right-btn {
      margin-left: 0;
      margin-top: 8px;
    }
  }
}
</style>

小結(jié)

本文主要寫了一個可拖動排序的穿梭框組件,更多關(guān)于拖動穿梭框CustormTransfer vue的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue-router4版本第一次打開界面不匹配路由問題解決

    vue-router4版本第一次打開界面不匹配路由問題解決

    本文主要介紹了vue-router4版本第一次打開界面不匹配路由問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • bmob js-sdk 在vue中的使用教程

    bmob js-sdk 在vue中的使用教程

    將bmob js-sdk放在static目錄,然后在index.html頁面中已 script 標(biāo)簽的形式引入,就可以在vue中全局使用bmob js-sdk。下面通過本文給大家分享bmob js-sdk 在vue中的使用教程,需要的朋友參考下吧
    2018-01-01
  • Vue如何接入hls/m3u8的直播視頻詳解

    Vue如何接入hls/m3u8的直播視頻詳解

    項目中有一個需求,需要實(shí)現(xiàn)直播功能,后端接口返回的是m3u8數(shù)據(jù)流,下面這篇文章主要給大家介紹了關(guān)于Vue如何接入hls/m3u8直播視頻的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • vue 使用class創(chuàng)建和清除水印的示例代碼

    vue 使用class創(chuàng)建和清除水印的示例代碼

    這篇文章主要介紹了vue 使用class創(chuàng)建和清除水印的示例代碼,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2020-12-12
  • vue中子組件如何間接修改父組件傳遞過來的值問題

    vue中子組件如何間接修改父組件傳遞過來的值問題

    這篇文章主要介紹了vue中子組件如何間接修改父組件傳遞過來的值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Vue快速實(shí)現(xiàn)通用表單驗證的示例代碼

    Vue快速實(shí)現(xiàn)通用表單驗證的示例代碼

    這篇文章主要介紹了Vue快速實(shí)現(xiàn)通用表單驗證的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • Vue報錯ERR_OSSL_EVP_UNSUPPORTED解決方法

    Vue報錯ERR_OSSL_EVP_UNSUPPORTED解決方法

    Vue項目啟動時報錯ERR_OSSL_EVP_UNSUPPORTED,本文主要介紹了Vue報錯ERR_OSSL_EVP_UNSUPPORTED解決方法,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • vue history 模式打包部署在域名的二級目錄的配置指南

    vue history 模式打包部署在域名的二級目錄的配置指南

    這篇文章主要介紹了vue history 模式打包部署在域名的二級目錄的配置指南 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • vue自定義一個v-model的實(shí)現(xiàn)代碼

    vue自定義一個v-model的實(shí)現(xiàn)代碼

    這篇文章主要介紹了vue自定義一個v-model的實(shí)現(xiàn)代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • Vue的移動端多圖上傳插件vue-easy-uploader的示例代碼

    Vue的移動端多圖上傳插件vue-easy-uploader的示例代碼

    這篇文章主要介紹了Vue的移動端多圖上傳插件vue-easy-uploader的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11

最新評論