国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Vue 可拖拽組件Vue Smooth DnD的使用詳解

發(fā)布時(shí)間:2021-08-17 12:16 來(lái)源: 閱讀:0 作者:wenr 欄目: JavaScript 歡迎投稿:712375056

目錄

簡(jiǎn)介和 Demo 展示

最近需要有個(gè)拖拽列表的需求,發(fā)現一個(gè)簡(jiǎn)單好用的 Vue 可拖拽組件。安利一下~

是一個(gè)快速、輕量級的拖放、可排序的 Vue.js 庫,封裝了 庫。

Vue Smooth DnD 主要包含了兩個(gè)組件,ContainerDraggable,Container 包含可拖動(dòng)的元素或組件,它的每一個(gè)子元素都應該被 Draggable 包裹。每一個(gè)要被設置為可拖動(dòng)的元素都需要被 Draggable 包裹。

安裝: npm i vue-smooth-dnd

一個(gè)簡(jiǎn)單的 Demo ,展示組件的基礎用法,實(shí)現了可以拖拽的列表。

<template>
    <div>
        <div class="simple-page">
            <Container @drop="onDrop">
                <Draggable v-for="item in items" :key="item.id">
                    <div class="draggable-item">
                        {{item.data}}
                    </div>
                </Draggable>
            </Container>
        </div>
    </div>
</template>

<script>
    import { Container, Draggable } from "vue-smooth-dnd";

    const applyDrag = (arr, dragResult) => {
        const { removedIndex, addedIndex, payload } = dragResult
        console.log(removedIndex, addedIndex, payload)
        if (removedIndex === null && addedIndex === null) return arr

        const result = [...arr]
        let itemToAdd = payload

        if (removedIndex !== null) {
            itemToAdd = result.splice(removedIndex, 1)[0]
        }

        if (addedIndex !== null) {
            result.splice(addedIndex, 0, itemToAdd)
        }

        return result
    }

    const generateItems = (count, creator) => {
        const result = []
        for (let i = 0; i < count; i++) {
            result.push(creator(i))
        }
        return result
    }

    export default {
        name: "Simple",
        components: { Container, Draggable },
        data() {
            return {
                items: generateItems(50, i => ({ id: i, data: "Draggable " + i }))
            };
        },
        methods: {
            onDrop(dropResult) {
                this.items = applyDrag(this.items, dropResult);
            }
        }
    };

</script>

<style>
    .draggable-item {
        height: 50px;
        line-height: 50px;
        text-align: center;
        display: block;
        background-color: #fff;
        outline: 0;
        border: 1px solid rgba(0, 0, 0, .125);
        margin-bottom: 2px;
        margin-top: 2px;
        cursor: default;
        user-select: none;
    }
</style>

效果

API: Container

屬性

關(guān)于 drag-class,drop-classdrop-placeholder.className 的效果演示

<Container # 省略其它屬性...
        :animation-duration="1000" # 放置元素后動(dòng)畫(huà)延時(shí)
        drag-class="card-ghost"         
        drop-class="card-ghost-drop"
        :drop-placeholder="{
            className: 'drop-preview',  # 占位符的樣式
            animationDuration: '1000', # 占位符的動(dòng)畫(huà)延遲
            showOnTop: true            # 是否在其它元素的上面顯示 設置為false會(huì )被其他的拖拽元素覆蓋
        }"
>
    <!-- 一些可拖拽元素 -->
    <Draggable>....</Draggable>
</Container>

類(lèi)對應樣式

.card-ghost {
    transition: transform 0.18s ease;
    transform: rotateZ(35deg);
    background: red !important;
}
.card-ghost-drop {
    transition: transform 1s cubic-bezier(0,1.43,.62,1.56);
    transform: rotateZ(0deg);
    background: green !important;
}
.drop-preview {
    border: 1px dashed #abc;
    margin: 5px;
    background: yellow !important;
}

實(shí)際效果(我這優(yōu)秀的配色?。?/p>

生命周期

一次拖動(dòng)的生命周期通過(guò)一系列回調和事件進(jìn)行描述和控制,下面以包含 3 個(gè)容器的示例為例進(jìn)行說(shuō)明
(直接復制了文檔沒(méi)有翻譯,API 詳細解釋可以看后面介紹。):

Mouse     Calls  Callback / Event       Parameters              Notes

down   o                                                        Initial click

move   o                                                        Initial drag
       |
       |         get-child-payload()    index                   Function should return payload
       |
       |   3 x   should-accept-drop()   srcOptions, payload     Fired for all containers
       |
       |   3 x   drag-start             dragResult              Fired for all containers
       |
       |         drag-enter
       v

move   o                                                        Drag over containers
       |
       |   n x   drag-leave                                     Fired as draggable leaves container
       |   n x   drag-enter                                     Fired as draggable enters container
       v

up     o                                                        Finish drag

                 should-animate-drop()  srcOptions, payload     Fires once for dropped container

           3 x   drag-end               dragResult              Fired for all containers

           n x   drop                   dropResult              Fired only for droppable containers

請注意,應在每次 drag-start 之前和每次 drag-end 之前觸發(fā) should-accept-drop,但為了清晰起見(jiàn),此處已省略。

其中 dragResult 參數的格式:

dragResult: {
    payload,        # 負載 可以理解為用來(lái)記錄被拖動(dòng)的對象
    isSource,       # 是否是被拖動(dòng)的容器本身
    willAcceptDrop, # 是否可以被放置
}

其中 dropResult 參數的格式:

dropResult: {
    addedIndex,     # 被放置的新添加元素的下標,沒(méi)有則為 null
    removedIndex,   # 將被移除的元素下標,沒(méi)有則為 null
    payload,        # 拖動(dòng)的元素對象,可通過(guò) getChildPayload 指定
    droppedElement, # 放置的 DOM 元素
}

回調

回調在用戶(hù)交互之前和期間提供了額外的邏輯和檢查。

  • get-child-payload(index) 自定義傳給 onDrop()payload 對象。
  • should-accept-drop(sourceContainerOptions, payload) 用來(lái)確定容器是否可被放置,會(huì )覆蓋 group-name 屬性。
  • should-animate-drop(sourceContainerOptions, payload) 返回 false 則阻止放置動(dòng)畫(huà)。
  • get-ghost-parent() 返回幽靈元素(拖動(dòng)時(shí)顯示的元素)應該添加到的元素,默認是父元素,某些情況定位會(huì )出現問(wèn)題,則可以選擇自定義,如返回 document.body。

事件

  • @drag-start 在拖動(dòng)開(kāi)始時(shí)由所有容器發(fā)出的事件。參數 dragResult。
  • @drag-end 所有容器在拖動(dòng)結束時(shí)調用的函數。 在 @drop 事件之前調用。參數 dragResult。
  • @drag-enter 每當拖動(dòng)的項目在拖動(dòng)時(shí)進(jìn)入其邊界時(shí),相關(guān)容器要發(fā)出的事件。
  • @drag-leave 每當拖動(dòng)的項目在拖動(dòng)時(shí)離開(kāi)其邊界時(shí),相關(guān)容器要發(fā)出的事件。
  • @drop-ready 當容器中可能放置位置的索引發(fā)生變化時(shí),被拖動(dòng)的容器將調用的函數?;旧?,每次容器中的可拖動(dòng)對象滑動(dòng)以打開(kāi)拖動(dòng)項目的空間時(shí)都會(huì )調用它。參數 dropResult。
  • @drop 放置結束時(shí)所有相關(guān)容器會(huì )發(fā)出的事件(放置動(dòng)畫(huà)結束后)。源容器和任何可以接受放置的容器都被認為是相關(guān)的。參數 dropResult。

API: Draggable

tag

同容器的 tag 指定可拖拽元素的 DOM 元素標簽。

實(shí)戰

實(shí)現一個(gè)簡(jiǎn)單的團隊協(xié)作任務(wù)管理器。

<template>
    <div class="card-scene">
        <Container
                orientation="horizontal"
                @drop="onColumnDrop($event)"
                drag-handle-selector=".column-drag-handle"
        >
            <Draggable v-for="column in taskColumnList" :key="column.name">
                <div class="card-container">
                    <div class="card-column-header">
                        <span class="column-drag-handle">&#x2630;</span>
                        {{ column.name }}
                    </div>
                    <Container
                            group-name="col"
                            @drop="(e) => onCardDrop(column.id, e)"
                            :get-child-payload="getCardPayload(column.id)"
                            drag-class="card-ghost"
                            drop-class="card-ghost-drop"
                            :drop-placeholder="dropPlaceholderOptions"
                            class="draggable-container"
                    >
                        <Draggable v-for="task in column.list" :key="task.id">
                            <div class="task-card">
                                <div class="task-title">{{ task.name }}</div>
                                <div class="task-priority" :style="{ background: priorityMap[task.priority].color }">
                                    {{ priorityMap[task.priority].label }}
                                </div>
                            </div>
                        </Draggable>
                    </Container>
                </div>
            </Draggable>
        </Container>
    </div>
</template>

<script>
    import { Container, Draggable } from "vue-smooth-dnd";

    const applyDrag = (arr, dragResult) => {
        const { removedIndex, addedIndex, payload } = dragResult
        console.log(removedIndex, addedIndex, payload)
        if (removedIndex === null && addedIndex === null) return arr

        const result = [...arr]
        let itemToAdd = payload

        if (removedIndex !== null) {
            itemToAdd = result.splice(removedIndex, 1)[0]
        }

        if (addedIndex !== null) {
            result.splice(addedIndex, 0, itemToAdd)
        }

        return result
    }

    const taskList = [
        {
            name: '首頁(yè)',
            priority: 'P1',
            status: '待開(kāi)發(fā)',
            id: 1,
        },
        {
            name: '流程圖開(kāi)發(fā)',
            priority: 'P3',
            status: '待評審',
            id: 2,
        },
        {
            name: '統計圖展示',
            priority: 'P0',
            status: '開(kāi)發(fā)中',
            id: 3,
        },
        {
            name: '文件管理',
            priority: 'P1',
            status: '開(kāi)發(fā)中',
            id: 4,
        }
    ]

    const statusList = ['待評審', '待開(kāi)發(fā)', '開(kāi)發(fā)中', '已完成']

    const taskColumnList = statusList.map((status, index) => {
        return {
            name: status,
            list: taskList.filter(item => item.status === status),
            id: index
        }
    })

    const priorityMap = {
        'P0': {
            label: '最高優(yōu)',
            color: '#ff5454',
        },
        'P1': {
            label: '高優(yōu)',
            color: '#ff9a00',
        },
        'P2': {
            label: '中等',
            color: '#ffd139',
        },
        'P3': {
            label: '較低',
            color: '#1ac7b5',
        },
    }

    export default {
        name: 'Cards',
        components: {Container, Draggable},
        data () {
            return {
                taskColumnList,
                priorityMap,
                dropPlaceholderOptions: {
                    className: 'drop-preview',
                    animationDuration: '150',
                    showOnTop: true
                }
            }
        },
        methods: {
            onColumnDrop (dropResult) {
                this.taskColumnList = applyDrag(this.taskColumnList, dropResult)
            },
            onCardDrop (columnId, dropResult) {
                let { removedIndex, addedIndex, payload } = dropResult
                if (removedIndex !== null || addedIndex !== null) {
                    const column = taskColumnList.find(p => p.id === columnId)
                    if (addedIndex !== null && payload) { // 更新任務(wù)狀態(tài)
                        dropResult.payload = {
                            ...payload,
                            status: column.name,
                        }
                    }
                    column.list = applyDrag(column.list, dropResult)
                }
            },
            getCardPayload (columnId) {
                return index =>
                    this.taskColumnList.find(p => p.id === columnId).list[index]
            },
        }
    }
</script>


<style>
    * {
        margin: 0;
        padding: 0;
        font-family: 'Microsoft YaHei','PingFang SC','Helvetica Neue',Helvetica,sans-serif;
        line-height: 1.45;
        color: rgba(0,0,0,.65);
    }
    .card-scene {
        user-select: none;
        display: flex;
        height: 100%;
        margin: 20px;
    }
    .card-container {
        display: flex;
        flex-direction: column;
        width: 260px;
        min-width: 260px;
        border-radius: 12px;
        background-color: #edeff2;
        margin-right: 16px;
        height: calc(100vh - 40px);
    }
    .card-column-header {
        display: flex;
        height: 50px;
        margin: 0 16px;
        align-items: center;
        flex-shrink: 0;
        font-weight: 500;
        font-size: 16px;
    }
    .draggable-container {
        flex-grow: 1;
        overflow: auto;
    }
    .column-drag-handle {
        cursor: move;
        padding: 5px;
    }
    .task-card {
        margin: 10px;
        background-color: white;
        padding: 15px 10px;
        border-radius: 8px;
        box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.12);
        cursor: pointer;
        display: flex;
        justify-content: space-between;
    }
    .task-title {
        color: #333333;
        font-size: 14px;
    }
    .task-priority {
        width: 60px;
        line-height: 20px;
        border-radius: 12px;
        text-align: center;
        color: #fff;
        font-size: 12px;
    }
    .card-ghost {
        transition: transform 0.18s ease;
        transform: rotateZ(5deg)
    }

    .card-ghost-drop {
        transition: transform 0.18s ease-in-out;
        transform: rotateZ(0deg)
    }

    .drop-preview {
        background-color: rgba(150, 150, 200, 0.1);
        border: 1px dashed #abc;
        margin: 5px;
    }
</style>

效果

到此這篇關(guān)于Vue 可拖拽組件Vue Smooth DnD的使用詳解的文章就介紹到這了,更多相關(guān)Vue 可拖拽組件內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

开心五月综合亚洲| 国产AⅤ无码专区亚洲AV| 久久精品夜色噜噜亚洲A∨| 青青青国产免A在线观看| 国内偷窥一区二区三区视频| 国产精品自产拍高潮在线观看|