2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
I haven't seen him for a long time. Recently, I met a product developer. He made a product for the first time. There are always some anti-human designs. That's right, it's the drag-and-drop collection on the title, and the swipe-left deletion of the product. I haven't found any such design in any major apps. He kept saying that he would show it to me if he had used it. I waited for a long time. Maybe he forgot.
When I encountered this kind of demand, I also tried to communicate with him, such as using the shopping cart to delete products, etc., and changing to some logic that everyone can accept, but he has his own ideas, so I have to choose to respect them.
After searching for the drag collection function for a long time, I used a drag and drop plug-in written by a great god and adapted it accordingly. Because my requirement does not require the displayed collection, the page jumps when the collection is collected, so there will be some modifications in the use, but it is similar overall. The following is the official website of the plug-in, you can refer to it:
vue.draggable Chinese Documentation - itxst.com
Note: When monitoring the start and end events of dragging during development, an error message will be displayed. If this happens, you can solve it yourself or use the same method as me to monitor the dragging process, etc. This varies depending on the needs. Finally, the code is attached:
- <template>
- <div id="app">
- <h1>商品列表</h1>
- <div class="container">
- <div class="row">
- <!-- @change="onDragEnd" @start="start" @end="onEnd" :move="onMove" delay="1000" -->
- <div class="col-md-6">
- <draggable v-model="leftItems" :group="group" delay="1000"
- @change="onDragEnd" :move="onMove"
- animation="300" dragClass="dragClass" ghostClass="ghostClass">
- <!-- <u-swipe-action :show="item.show" :index="index"
- v-for="(item, index) in leftItems" :key="item.id"
- @click="click" @open="open"
- :options="options"
- > -->
- <div class="item" v-for="(item, index) in leftItems" :key="item.id" >{{ item.name }}</div>
- <!-- </u-swipe-action> -->
- </draggable>
- </div>
-
- <div class="col-md-6">
- <draggable v-model="rightItems" :group="group"
- @change="onDragEnd" :move="onMove">
- <div v-for="(item, index) in rightItems" :key="index" @longpress="aaa(index)" :class="['item',item.status==true?'shake':'']">{{ item.name }}</div>
- </draggable>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import draggable from 'vuedraggable';
-
- export default {
- components: {
- draggable
- },
- data() {
- return {
- disabled: false,
- btnWidth: 180,
- show: false,
- options: [
- {
- text: '删除',
- style: {
- backgroundColor: '#dd524d'
- }
- }
- ],
- timerId: null,//计时器id
- group: {
- name: "itxst",
- pull: true, //可以拖出
- put: true, //可以拖入
- },
- leftItems: [{
- id: 1,
- show: false,
- status: false,
- name: '商品1'
- },
- {
- id: 2,
- show: false,
- status: false,
- name: '商品2'
- },
- {
- id: 3,
- show: false,
- status: false,
- name: '商品3'
- },
- {
- id: 4,
- show: false,
- status: false,
- name: '商品4'
- },
- {
- id: 5,
- show: false,
- status: false,
- name: '商品5'
- },
- {
- id: 6,
- show: false,
- status: false,
- name: '商品6'
- },
- ],
- rightItems: [{
- id: 1,
- show: false,
- status: false,
- name: '商品1'
- },
- {
- id: 2,
- show: false,
- status: false,
- name: '商品2'
- },
- {
- id: 3,
- show: false,
- status: false,
- name: '商品3'
- },
- {
- id: 4,
- show: false,
- status: false,
- name: '商品4'
- },
- {
- id: 5,
- show: false,
- status: false,
- name: '商品5'
- },
- {
- id: 6,
- show: false,
- status: false,
- name: '商品6'
- },
- ]
- };
- },
- onLoad() {
-
- },
- methods: {
- click(index) {
- this.leftItems.splice(index, 1);
- this.$u.toast(`删除了第${index}个cell`);
- },
- // 如果打开一个的时候,不需要关闭其他,则无需实现本方法
- open(index) {
- // 先将正在被操作的swipeAction标记为打开状态,否则由于props的特性限制,
- // 原本为false,再次设置为false会无效
- this.leftItems[index].show = true;
- this.leftItems.map((val, idx) => {
- if(index != idx) this.leftItems[idx].show = false;
- })
- },
-
- start(e) {
- console.log(e, 'kasihi ');
- },
- onEnd() {
- console.log(e, '结束了 ');
- },
- onMove(e) { // keyi huanyuan
- clearTimeout(this.timerId)
- console.log('如果能监听到要在这里清楚计时器');
- return this.canFormSet()
- },
- aaa(index) {
- this.rightItems[index].status = true
- this.timerId = setTimeout(() => {
- this.rightItems[index].status = false
- clearTimeout(this.timerId)
- }, 500)
- },
- onDragEnd(event) {
- console.log(event);
- // if (event.newIndex !== event.oldIndex) {
- // const movedItem = this.leftItems[event.oldIndex];
- // this.leftItems.splice(event.oldIndex, 1);
- // this.rightItems.push(movedItem);
- // 判断是否可以形成集合跳转页面
- if (this.canFormSet()) {
- // 跳转到另一个页面的逻辑
- console.log('路由去往新的页面');
- // this.$router.push('/another-page');
- } else {
- // 如果不能形成集合,则复原
- console.log('复原');
-
- // this.rightItems.pop();
- // this.leftItems.splice(event.newIndex, 0, movedItem);
- }
- console.log('6666');
- clearTimeout(this.timerId)
- // } else {
- // console.log('else');
- // // Revert the move if it's not a valid combination
- // const movedItem = this.rightItems.pop();
- // this.leftItems.splice(event.newIndex, 0, movedItem);
- // }
- },
-
- canFormSet() {
- // 如果可以形成集合,返回 true;否则返回 false
- return false; // 示例中默认返回 true
- }
- }
- };
- </script>
-
- <style scoped lang="scss">
- .shake {
- width: 100px;
- height: 100px;
- background-color: red;
- transform-origin: center;
- animation: shake .5s infinite ease-in-out;
- }
-
- @keyframes shake {
-
- 0%,
- 100% {
- transform: rotate(-5deg);
- /* transform: translate(-50%, -50%) rotate(-5deg); */
- }
-
- 50% {
- transform: rotate(5deg);
- }
- }
-
- .ghostClass {
- background-color: blue !important;
- }
-
- .chosenClass {
- background-color: red !important;
- opacity: 1 !important;
- }
-
- .dragClass {
- background-color: blueviolet !important;
- opacity: 1 !important;
- box-shadow: none !important;
- outline: none !important;
- background-image: none !important;
- }
-
- .container {
- width: 100%;
- margin-top: 20px;
- }
- .row {
- width: 100%;
- display: flex;
- }
- .col-md-6 {
- width: 100%;
- // display: flex;
- // flex-wrap: wrap;
- }
-
- .item {
- width: 100px;
- height: 100px;
- margin-left: 20px;
- border: 1px solid #ccc;
- padding: 10px;
- margin-bottom: 10px;
- background-color: #f9f9f9;
- }
- </style>
As you can see from the code above, I plan to use u-swipe-action To implement the slide-to-delete function, but it can only slide to delete in one row. So I looked at the source code, and then I had an epiphany, and I wrote a code for multiple deletion effects in one row. I will also make some optimizations later. Without further ado, I will give you the code for reference, I hope it can help you:
- <template>
- <view class="container">
- <movable-area class="box-info"
- v-for="(item, index) in items"
- :key="index">
- <movable-view
- style="width: 140px; height: 100px; background-color: #aa55ff;"
- :style="{widh}"
- :x="index * 10"
- :direction="'horizontal'"
- :out-of-bounds="false"
- >
- <view class="product">
- <view style="width: 100px;">{{item}}</view>
- <view class="move" @click="removeShop">删除</view>
- </view>
- </movable-view>
- </movable-area>
- </view>
- </template>
-
- <script>
- export default {
- data() {
- return {
- items: ['商品1', '商品2']
- };
- },
- methods: {
- removeShop(index) {
- alert('删除商品操作')
- }
- }
- };
- </script>
-
- <style scoped lang="scss">
- .container {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- .box-info {
- display: flex;
- flex-wrap: wrap;
- height: 100px;
- width: 100px;
- background-color: #55ff7f;
- overflow: hidden;
- margin: 20px;
- .product {
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 14px;
- color: #333;
- .move{
- background-color: #55aa00;
- width: 40px;
- height: 100px;
- writing-mode: vertical-rl;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- }
- }
- }
- </style>