Vue 实现多图上传并可以调整图片顺序

文章目录

    由于 Element UI 的 Upload 上传组件只支持多图上传,但并不支持图片的顺序调整,而实际使用场景中,例如,产品封面轮播图,经常要用到图片顺序调整功能。所以,找了一下解决方案。

    一些备选方案

    JQuery UI sortable

    效果演示,参考:https://codepen.io/malkafly/pen/gbVYZb

    上面示例中使用的排序组件是 jquery ui 中的 sortable 功能。

    但是,我测试的过程中,感觉 jquery ui 的这个功能非常不流畅,经常出现没有响应的情况。

    Sortablejs

    找到一个竞品 sortablejs, 从对比视频上看,优化效果明显。里面有视频演示,及对比:https://sortablejs.github.io/Sortable/

    而且有 vue 版本的实现。

    Vue draggable 项目地址:https://github.com/SortableJS/Vue.Draggable

    带删除按钮的 vue draggable 实现:https://jsfiddle.net/dede89/5Leuhh1n/

    代码实现

    我觉得使用 Element UI upload 组件结合 Vue draggable 来实现上传后的图片调整顺序。

    补充:结合使用,还间接修复了一个 Element UI upload 的一个巨大缺陷,即,无法同时上传多张图片。因为,选择多张图片上传时,upload 组件的 on-success 回调,只会被调用一次。最简单的解决方案是,将 file-list 去掉,引入了 draggable 之后,不再需要 upload 组件来管理删除,和排序,所有 file-list 去掉,没有任何额外工作量。

    查看 Demo 效果页面

    效果 Gif 截图:

    Vue 实现多图上传并可以调整图片顺序

    实现代码

    注意,这是一个基于 Laravel PHP 模板的代码,vue 变量为了避免冲突,在变量前加上了 @ 符号。转换的时候,需要去掉

    模板代码

    <!DOCTYPE html>
    <html lang="zh-CN">
    
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Element UI 上传组件结合 Vue Draggable 实现拖拽排序</title>
        <meta name="description" content="">
        <meta name="keywords" content="">
    
        <!-- Set render engine for 360 browser -->
        <meta name="renderer" content="webkit">
    
        <!-- 禁止百度移动搜索转码 -->
        <meta http-equiv="Cache-Control" content="no-transform" />
        <meta http-equiv="Cache-Control" content="no-siteapp" />
    
        <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.4.0/css/bootstrap.min.css" />
        <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.4.11/theme-chalk/index.css" />
        <link rel="stylesheet" href="https://cdn.staticfile.org/animate.css/3.7.0/animate.min.css" />
        <link rel="stylesheet" href="{{ URL::asset('css/footer.css') }}?t=201812061243">
    
        <style type="text/css">
            input.el-upload__input {
              display: none;
            }
        </style>
    </head>
    
    <body>
        <div class="container" style="margin-bottom: 20px;">
            <h1>Element UI 上传组件结合 Vue Draggable 实现拖拽排序</h1>
        </div>
    
        <div class="container" id="upload_images">
            <p>
            由于默认的 Element UI upload 组件不支持多图上传后的拖拽排序。
            </p>
            <p>
            所以,测试一下 Element UI upload 组件 + Vue Draggable 来实现排序功能。
            </p>
            <p>
            Vue Draggable 是基于 sortablejs 实现的,所以操作体验上相对 jQuery UI Sortable 要流畅很多。
            </p>
            <div class="row">
                <div class="col-sm-12 col-md-12 main">
    				<el-upload
                         class="upload-demo"
                         action=""
                         multiple
                         :limit="10"
                         :on-success="handle_success"
                         list-type="picture-card"
                         :file-list="images">
                          <el-button size="small" type="primary">点击上传</el-button>
                          <div slot="tip" class="el-upload__tip">上方为 element ui upload 组件自带的列表样式,不支持拖拽排序</div>
    				</el-upload>
    
    				<div class="drag">
    					<h2>Vue Draggable - 可在下方尝试拖拽</h2>
                        <ul class="el-upload-list el-upload-list--picture-card">
                          <draggable v-model="images" class="dragArea">
                            <li :tabindex="index" class="el-upload-list__item is-success animated" style=""
                                v-for="(element, index) in images"
                                v-bind:class="{flash: element.to_del}"
                                >
                                <img :src="element.url" alt="" class="el-upload-list__item-thumbnail ">
                                <a class="el-upload-list__item-name">
                                    <i class="el-icon-document"></i>
                                    @{{element.name}}
                                </a>
                                <label class="el-upload-list__item-status-label">
                                    <i class="el-icon-upload-success el-icon-check"></i>
                                </label>
                                <i class="el-icon-close"></i>
                                <span class="el-upload-list__item-actions"><!---->
                                    <span class="el-upload-list__item-delete">
                                        <i class="el-icon-delete" @click="remove(index)"></i>
                                    </span>
                                </span>
                            </li>
                          </draggable>
                        </ul>
    				</div>
    
                    <div style="margin-bottom: 50px;">
    					<h2>列表数据</h2>
                        <div >
                            <p v-for="(element, index) in images">
                                @{{element.name}} - @{{element.url}}
                            </p>
                        </div>
                    </div>
    
                </div>
            </div>
        </div>
    
        <script type="text/javascript" src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js"></script>
        <script type="text/javascript" src="https://cdn.staticfile.org/Sortable/1.8.1/Sortable.min.js"></script>
        <script type="text/javascript" src="https://cdn.staticfile.org/Vue.Draggable/2.17.0/vuedraggable.min.js"></script>
        <script type="text/javascript" src="https://cdn.staticfile.org/element-ui/2.4.11/index.js"></script>
        <script type="text/javascript" src="{{ asset('js/upload_images_and_sort.js') }}?t=201901212007"></script>
    </body>
    
    </html>
    
    

    vuejs 代码

    new Vue({
      el: "#upload_images",
    
      data: {
        images: [
          {
            name: 'img1',
            to_del: false,      // 纯粹为了删除特效,可不加
            url: 'http://temp.im/401x401/4CD964/fff'
          },
          {
            name: 'img2',
            to_del: false,
            url: 'http://temp.im/402x402/4CD964/fff'
          },
          {
            name: 'img3',
            to_del: false,
            url: 'http://temp.im/403x403/4CD964/fff'
          },
          {
            name: 'img4',
            to_del: false,
            url: 'http://temp.im/404x404/4CD964/fff'
          }
        ]
      },
    
      mounted: function() {
      },
    
      methods: {
        handle_success: function() {
        },
    
        remove: function(index) {
          var that = this;
          this.$confirm('确认删除?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(function () {
            that.$message({
              type: 'success',
              message: '删除成功!'
            });
            that.images[index].to_del = true;
            setTimeout(function() {
              that.images.splice(index, 1);
            }, 1000);
          })
        }
      }
    })
    

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式