vue2 使用 Sortable 库进行拖拽操作

2023-11-08

一、vue 项目使用

文档地址: https://www.itxst.com/sortablejs/neuinffi.html

1、安装依赖

npm i -S vuedraggable

2、.vue 文件引入组件

import draggable from "vuedraggable";
components: { draggable },

在这里插入图片描述

3、.使用

查看文档中的示例即可:https://debug.itxst.com/js/ivv3eivm

我们使用的 npm 安装,不需要其他东西,只需要下方标注的主要代码部分,其中的css为演示展示用,无实际用处

在这里插入图片描述

二、进阶案例演示代码(UMD版)

1、采用技术

  • vue2
  • element-ui2
  • avue : 基于vue2 + element-ui2 二次封装组件库
  • Sortable : 拖拽
  • vuedraggable : vue二次封装的拖拽,基于Sortable

2、展示图

在这里插入图片描述

3、源码

原为npm 版, 抽取成 UMD 版便于大家学习参考

1、本地新建 .html文件
2、复制下方代码到 .html
3、打开htm 即得到上方 展示效果中 相同效果

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<!-- 引入样式文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@smallwei/avue/lib/index.css"/>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"/>
<!-- 引入相关JS 文件 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@smallwei/avue/lib/avue.min.js"></script>

<!-- 图片拖拽排序 -->
<script src="https://cdn.staticfile.org/Sortable/1.10.0-rc2/Sortable.min.js"></script>
<!-- 已经加载过了 -->
<!--<script src="https://www.itxst.com/package/vue/vue.min.js"></script>-->
<!--<script src="https://www.itxst.com/package/sortable/Sortable.min.js"></script>-->
<script src="https://www.itxst.com/package/vuedraggable/vuedraggable.umd.min.js"></script>


<div id="app">
    {{ message }}

    <div class="bt-article-all">
        <el-row>
            <el-col :span="24">
                <el-card class="box-card">
                    <div slot="header" class="clearfix">
                        <span>文章信息区</span>
                        <el-button style="float: right; padding: 3px 0" type="text">保存</el-button>
                    </div>
                    <avue-form ref="form" v-model="obj" :option="option"
                               @reset-change="emptytChange"
                               @submit="submit">
                        <template slot-scope="{row}" slot="content">
                            <TinymceEditor v-if="initSuccess" :content.sync="obj.content"/>
                        </template>
                    </avue-form>
                </el-card>
            </el-col>
        </el-row>


        <el-row>

            <!-- 左侧区 -->
            <el-col :span="12">
                <el-card class="box-card">
                    <div slot="header" class="clearfix">
                        <span>内容编辑区</span>
                        <!-- <el-button style="float: right; padding: 3px 0" type="text">保存</el-button>-->
                    </div>
                    <div>
                        <!--  group="itxst" -->
                        <draggable v-model="contentItems" chosen-class="chosen" force-fallback="true" group="itxst" :disabled="disabledDrag" animation="1000" @start="onStart" @end="onEnd">
                            <transition-group>
                                <div id="contentBox" class="bt-card-box" v-for="(item,index) in contentItems" :key="index" style="padding-top: 2%">
                                    <el-card class="box-card bt-card-box">
                                        <div slot="header" class="clearfix singlePerson">
                                            <span>{{index+1}} :   </span>
                                            <span>{{item.lableName}}  </span>
                                            <el-button style="float: right; padding: 3px 0" type="text" @click="delItemRow(item)">删除</el-button>
                                        </div>
                                        <div v-if="item.lable == 'H1' || item.lable == 'H2' || item.lable == 'H3'">
                                            <el-input type="input" placeholder="请输入内容" v-model="item.value"></el-input>
                                        </div>
                                        <div v-if="item.lable == 'P' ">
                                            富文本组件
                                            <!-- 富文本组件 当前单页无法加载 -->
                                            <!--  <TinymceEditor v-if="drag==false" :content.sync="item.value"/>-->
                                        </div>
                                        <div v-if="item.lable == 'IMAGE'">
                                            <el-image style="width: 80px; height: 80px" :src="item.value" fit="cover"></el-image>
                                        </div>
                                        <div v-if="item.lable == 'VIDEO'">
                                            <el-input type="input" placeholder="请输入内容" v-model="item.value"></el-input>
                                            <!--  <el-image style="width: 80px; height: 80px" :src="item.value" fit="cover"></el-image>-->
                                        </div>
                                        <div v-if="item.lable == 'ARRAY'">
                                            <!-- <avue-form :option="{column: [{label:'数组框',prop:'array', type:'array', value:[0,1]}]}"></avue-form>-->
                                            <avue-array v-model="item.value" :option="{dataType:'string'}" placeholder="请输入内容"></avue-array>
                                        </div>
                                    </el-card>
                                </div>
                            </transition-group>
                        </draggable>
                    </div>
                </el-card>
            </el-col>

            <!-- 右侧区 -->
            <el-col :span="12">
                <!-- 媒体区 -->
                <div class="bt-card-box">
                    <el-card class="box-card">
                        <div slot="header" class="clearfix">
                            <span>媒体资源区</span>
                        </div>
                        <div>
                            <el-row>
                                <draggable v-model="imageItems" chosen-class="chosen" force-fallback="true" :options="{group:{name: 'itxst',pull:'clone'}, sort: true}" animation="1000" @start="onStartImages" @end="onEndImages">
                                    <transition-group>
                                        <el-col :span="4" v-for="(item,index) in imageItems" :key="index">
                                            <div style="padding: 5%">
                                                <el-card class="box-card">
                                                    <el-image
                                                            style="width: 80px; height: 80px"
                                                            :src="item.value"
                                                            fit="cover"></el-image>
                                                    <span style="text-align: center;display:block;">{{ item.alt }}</span>
                                                </el-card>
                                            </div>
                                        </el-col>
                                    </transition-group>
                                </draggable>
                            </el-row>
                        </div>
                    </el-card>
                </div>

                <!-- 内容预览区 -->
                <div class="bt-card-box" style="padding-top: 2%">
                    <el-card class="box-card">
                        <div slot="header" class="clearfix">
                            <span>内容预览区</span>
                        </div>
                        <div v-for="(item,index) in contentItems" :key="index">
                            <h1 v-if="item.lable == 'H1'">{{item.value}}</h1>
                            <h2 v-if="item.lable == 'H2'">{{item.value}}</h2>
                            <h3 v-if="item.lable == 'H3'">{{item.value}}</h3>
                            <span v-if="item.lable == 'P'" v-html="item.value"></span>
                            <span v-if="item.lable == 'IMAGE'">
                                <img style="width: 50%" :src="item.value" alt="item.alt">
                            </span>
                            <div v-if="item.lable == 'VIDEO'">
                                <video width="50%" controls :autoplay="false">
                                    <source :src="item.value" type="video/mp4">
                                </video>
                            </div>
                            <div v-if="item.lable == 'ARRAY'">
                                <li v-for="(item,index) in item.value">{{index+1}}{{item}}</li>
                            </div>
                        </div>
                    </el-card>
                </div>

            </el-col>
        </el-row>
        {{contentItems}}
        <div>{{drag?'拖拽中':'拖拽停止'}}</div>

    </div>
</div>

<body>
<script>
    //import draggable from "vuedraggable";

    var vm = new Vue({
        // 绑定 id="app" 的元素
        el: "#app",
        // components: {
        //     draggable
        // },
        // 定义数据
        data: {
            message: "这是一个拖拽示例demo",
            obj: {},
            initSuccess: false,
            defaultData: {
                name: null,
                alias: null,
                author: "测试",
                categoryIds: null,
                coverUrl: "http://xijia-sz.oss-cn-shenzhen.aliyuncs.com/oss/file/file/gc/08769453-1(6).jpeg",
                lables: null,
                content: null,
                state: 1,
                describe: "-",
                auth: 1,
                sort: 0,
                seoTitle: null,
                seoKeyword: null,
                seoDescription: null,

            },
            categoryTree: [],
            disabledDrag: false, //默认开启拖拽
            drag: false,
            dragImages: false,
            contentItems: [
                {lable: 'H1', lableName: "一级标题", value: ''},
                {lable: 'H2', lableName: "二级标题", value: ''},
                {lable: 'H3', lableName: "三级标题", value: ''},
                {lable: 'P', lableName: "段落", value: ''},
                {lable: 'IMAGE', lableName: "图片", value: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'},
                {lable: 'VIDEO', lableName: "视频", value: 'http://127.0.0.1:10006/upload/video/swagger-ui.html/20221109-0315-11、恭喜你发现宝藏!!!.mp4'},
                {lable: 'ARRAY', lableName: "有序列表", value: [0, 1]},

            ],
            // "lable": "H1", "name": "一级标题", "sort": 1, "value": "-"
            imageItems: [
                //fits: ['fill', 'contain', 'cover', 'none', 'fill'],
                //fits: ['fill', 'contain', 'cover', 'none', 'scale-down'],
                {lable: "IMAGE", lableName: "图片", alt: "a1", value: "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"},
                {lable: "IMAGE", lableName: "图片", alt: "a2", value: "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"},
                {lable: "IMAGE", lableName: "图片", alt: "a3", value: "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"},
                {lable: "IMAGE", lableName: "图片", alt: "a4", value: "http://xijia-sz.oss-cn-shenzhen.aliyuncs.com/oss/file/file/gc/08769453-1(6).jpeg"},
                {lable: "IMAGE", lableName: "图片", alt: "a5", value: "http://xijia-sz.oss-cn-shenzhen.aliyuncs.com/oss/file/file/gc/08769453-1(6).jpeg"},
                {lable: "IMAGE", lableName: "图片", alt: "a6", value: "http://xijia-sz.oss-cn-shenzhen.aliyuncs.com/oss/file/file/gc/08769453-1(6).jpeg"},
            ],
        },
        props: {
            closeDialog: [],
            uri: {},
        },
        computed: {
            option() {
                return {
                    submitBtn: false,
                    emptyBtn: false,
                    submitText: '提交',
                    emptyText: "关闭",
                    group: [
                        {
                            // icon: 'el-icon-info',
                            label: '展开/收缩文章信息',
                            collapse: false,
                            prop: 'group1',
                            column: [

                                {
                                    label: '文章名',
                                    prop: 'name',
                                    maxlength: 64,
                                    showWordLimit: true,
                                    span: 10,
                                    rules: [{
                                        required: true,
                                        message: "请输入 文章名",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: '别名',
                                    prop: 'alias',
                                    maxlength: 64,
                                    showWordLimit: true,
                                    span: 10,
                                    rules: [{
                                        required: true,
                                        message: "请输入 别名",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: '作者',
                                    prop: 'author',
                                    maxlength: 32,
                                    showWordLimit: true,
                                    span: 10,
                                    rules: [{
                                        required: true,
                                        message: "请输入 作者",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: '分类',
                                    prop: 'categoryIds',
                                    span: 10,
                                    type: "cascader",
                                    dataType: 'string',
                                    filterable: true,
                                    dicData: this.categoryTree,   // 自行替换字典数据
                                    props: {
                                        value: "id",
                                        label: "name",
                                        children: "categorys"
                                    },
                                    rules: [{
                                        required: true,
                                        message: "请选择 分类ids ",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: '封面图',
                                    prop: 'coverUrl',
                                    span: 10,
                                    rules: [{
                                        required: true,
                                        message: "请上传 文章封面图url ",
                                        trigger: "blur"
                                    }],
                                    dataType: 'string',
                                    accept: 'image/png, image/jpeg, image/jpg, image/gif',
                                    type: 'upload',
                                    listType: 'picture-img',
                                    action: '128.0.0.1/update/image/cover/',   // 上传地址 + 文件保存上传地址(详见接口描叙)
                                    multiple: true,          // 文件多选
                                    drag: true,              // 拖拽排序
                                    limit: 1,                // 上传数量 1 个
                                    //fileSize: 500,         // 上传大小 500 kb内
                                    tip: '只能上传 jpg/png/gif 格式的图片',
                                    loadText: '上传中...',
                                    propsHttp: {
                                        res: 'data'
                                    },
                                    uploadBefore: (file, done) => {
                                        // 文件上传前处理
                                        done(file)
                                    },
                                    uploadAfter: (res, done) => {
                                        this.$message.success('上传成功');
                                        done()
                                    },
                                    uploadError(error, column) {
                                        // 上传失败
                                        this.$message.error(error);
                                    },
                                    uploadExceed(limit, files, fileList, column) {
                                        // 文件数量验证
                                        this.$message.warning(`当前限制文件数量为 $1, 当前共 ${files.length + fileList.length} `);
                                    },
                                },
                                // {
                                //     label: '标签',
                                //     prop: 'lables',
                                //     type: 'array',
                                //     dataType: 'string',
                                //     limit: 10,
                                //     span: 10,
                                //     rules: [{
                                //         required: false,
                                //         message: "请添加 标签集",
                                //         trigger: "blur"
                                //     }]
                                // },
                                {
                                    label: '文章描述',
                                    prop: 'describe',
                                    type: 'textarea',
                                    maxlength: 256,
                                    showWordLimit: true,
                                    span: 10,
                                    rules: [{
                                        required: true,
                                        message: "请输入 文章描述",
                                        trigger: "blur"
                                    }]
                                },
                                // {
                                //     label: '文章内容 ',
                                //     prop: 'content',
                                //     maxlength: 0,
                                //     showWordLimit: true,
                                //     span: 10,
                                //     rules: [{
                                //         required: true,
                                //         message: "请输入 文章内容 ",
                                //         trigger: "blur"
                                //     }]
                                // },
                                // {
                                //     label: '状态 ',
                                //     prop: 'state',
                                //     type: 'radio',
                                //     //dicData: this.dict.get('ARTICLE_STATE'),
                                //     span: 10,
                                //     rules: [{
                                //         required: true,
                                //         message: "请选择 状态 ",
                                //         trigger: "blur"
                                //     }]
                                // },
                                // {
                                //     label: '访问权限 ',
                                //     prop: 'auth',
                                //     type: 'radio',
                                //     //dicData: this.dict.get('ARTICLE_AUTH'),
                                //     span: 10,
                                //     rules: [{
                                //         required: true,
                                //         message: "请选择 访问权限 ",
                                //         trigger: "blur"
                                //     }]
                                // },
                                // {
                                //     label: '排序',
                                //     prop: 'sort',
                                //     maxlength: 11,
                                //     showWordLimit: true,
                                //     span: 10,
                                //     rules: [{
                                //         required: true,
                                //         message: "请输入 排序",
                                //         trigger: "blur"
                                //     }]
                                // },
                                {
                                    label: 'seo: Title',
                                    prop: 'seoTitle',
                                    maxlength: 128,
                                    showWordLimit: true,
                                    span: 20,
                                    labelWidth: 130,
                                    rules: [{
                                        required: false,
                                        message: "请输入 seo优化字段 Title",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: 'seo: Keyword',
                                    prop: 'seoKeyword',
                                    maxlength: 256,
                                    showWordLimit: true,
                                    span: 20,
                                    labelWidth: 130,
                                    rules: [{
                                        required: false,
                                        message: "请输入 seo优化字段 Keyword",
                                        trigger: "blur"
                                    }]
                                },
                                {
                                    label: 'seo: Description',
                                    prop: 'seoDescription',
                                    maxlength: 256,
                                    showWordLimit: true,
                                    span: 20,
                                    labelWidth: 130,
                                    rules: [{
                                        required: false,
                                        message: "请输入 seo优化字段 Description",
                                        trigger: "blur"
                                    }]
                                }]
                        }],

                }
            }
        },
        created() {
            this.obj = this.defaultData;
            //this.findCategorTree();
            this.initSuccess = true;


        },
        // 实例被挂载后调用
        mounted: function () {
            console.log("mounted=实例已被挂载")
            // 输入内容时禁止拖拽
            var inputs = document.getElementsByClassName('el-input__inner');
            for (let item of inputs) {
                item.addEventListener('blur', event => {
                    console.log("inputting!!111");
                    this.disabledDrag = false;
                });
                item.addEventListener('focus', event => {
                    console.log("inputting!!222");
                    this.disabledDrag = true;
                });
            }

        },
        methods: {
            emptytChange() {
                this.closeDialog(false);
            }
            ,
            submit(form, done) {
                this.crud.post(this.uri.info, this.obj).then((res) => {
                    console.debug(res);
                    if (res.data.code == 200) {
                        this.closeDialog(true);
                    }
                    done(form);
                }).catch((err) => {
                    console.error(err);
                    done(form);
                })
            }
            ,
            /**
             * 查询分类数据
             */
            async findCategorTree() {
                let res = await this.crud.get(this.uri.findCategoryTree);
                this.categoryTree = res.data.data;
            }
            ,

            /**
             * 删除行数据
             * @param element
             */
            delItemRow(item) {
                if (this.contentItems.length <= 1) {
                    this.$message.error('最后一条数据不能删除');
                    return
                }
                this.contentItems.splice(this.contentItems.indexOf(item), 1)
            }
            ,

            // 内容区拖动
            onStart() {
                this.drag = true;
            }
            ,
            onEnd() {
                // this.resetImageSort();
                this.drag = false;
            }
            ,
            // 图片区拖动
            onStartImages() {
                this.dragImages = true;
            }
            ,
            onEndImages() {
                this.dragImages = false;
            }
            ,
        }
    });
    // app.use(AVUE);

</script>


<style scoped>
    /* 主宽度 */
    .bt-article-all {
        width: 96%;
        padding-left: 2%;
    }

    /* 卡片上间距 */
    .bt-card-box {
        padding-left: 1%;
    }

    /* 卡片默认样式 */
    .text {
        font-size: 14px;
    }

    .clearfix:before,
    .clearfix:after {
        display: table;
        content: "";
    }

    .clearfix:after {
        clear: both
    }

    .box-card {
        width: 100%;
        /*padding: 1%;*/
        padding-top: 1%;
    }
</style>


</body>
</html>

  • 个人开源项目(通用后台管理系统)–> https://gitee.com/wslxm/xijia-plus , 喜欢的可以看看

  • 本文到此结束,如果觉得有用,动动小手点赞或关注一下呗,将不定时持续更新更多的内容…,感谢大家的观看!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue2 使用 Sortable 库进行拖拽操作 的相关文章

随机推荐

  • 微信小程序事件和页面跳转

    一 页面跳转 1 非TabBar页面 一个小程序拥有多个页面 我们通过wx navigateTo进入一个新的页面 我们通过下边点击事件实现页面跳转进行代码实现及参考 wx navigateBack 回退到上一个页面 wx redirectT
  • 【单片机毕业设计】【mcuclub-310】红外遥控器

    设计简介 项目名 基于单片机的红外遥控器的设计 标准版 单片机 STC89C52 功能简介 1 利用红外发射电路 通过按不同的按键发送不同的数据值 2 利用红外接收电路 接收发送端发送的数据 3 通过数码管显示数据 资料预览 效果图 发送端
  • MiniGPT-4本地部署的实战方案

    大家好 我是herosunly 985院校硕士毕业 现担任算法研究员一职 热衷于机器学习算法研究与应用 曾获得阿里云天池比赛第一名 CCF比赛第二名 科大讯飞比赛第三名 拥有多项发明专利 对机器学习和深度学习拥有自己独到的见解 曾经辅导过若
  • Ubuntu22下OpenCV4.6.0+contrib模块编译安装

    目录 第一章 Ubuntu22下OpenCV4 6 0 contrib模块编译安装 第二章 ubuntu22下C kdevelop环境搭建 OpenCV示例 第三章 C 下OPENCV驱动调用海康GigE工业相机 文章目录 目录 Ubunt
  • K8S常用资源认识

    文章目录 一 Namespace 二 Pod 三 Label 四 Deployment 五 Service 一 Namespace namespace是kubernetes系统中的一种非常重要的资源 它的主要作用是用来实现多套环境的资源隔离
  • 基于栈与基于寄存器的指令集架构

    用C的语法来写这么一个语句 C代码 a b c 如果把它变成这种形式 add a b c 那看起来就更像机器指令了 对吧 这种就是所谓 三地址指令 3 address instruction 一般形式为 op dest src1 src2
  • python 模块和包

    文章目录 前言 模块 什么是模块 导入模块 import 导入模块 from 模块名 import 功能 from 模块名 import as定义别名 制作模块 模块的定位顺序 all 包 导入包 import 包名 模块 导入包 from
  • 打开Ubuntu18.04出现启动紫屏卡死不弹登录框问题

    1 进入grub高级模式 重启虚拟机 按esc进入 按 进入Ubuntu高级选项 2 选择recovery mode 3 选择root shell会话 输入root密码 4 编辑 etc gdm3 custom conf文件 将 Wayla
  • 5-快速排序

    假设有下面这样一排数据需要排序 3 7 6 1 2 9 1 2 6 排开常用的冒泡和选择排序 今天我们来试一下一种新的方法 快速排序 快速排序的思路如下 首先我们要先从这组数据中选出一个任意值X 然后以X为分界 比X小的数据排到X的左半边
  • Shiro之@RequiresPermissions注解原理详解

    前言 shiro为我们提供了几个权限注解 如下图 这几个注解原理都类似 这里我们讲解 RequiresPermissions的原理 铺垫 第一 首先要清楚 RequiresPermissions的基本用法 就是在Controller的方法里
  • python爬虫超时重试_python爬虫多次请求超时的几种重试方法(6种)

    第一种方法 headers Dict url https www baidu com try proxies None response requests get url headers headers verify False proxi
  • C#中的Dictionary简介

    简介 在C 中 Dictionary提供快速的基于键值的元素查找 当你有很多元素的时候可以使用它 它包含在System Collections Generic名空间中 在使用前 你必须声明它的键类型和值类型 详细说明 必须包含名空间Syst
  • tensorflow:使用全连接(full-connection)网络实现mnist

    tensorflow1 8 python3 6 4 coding utf 8 import tensorflow as tf import numpy as np from tensorflow examples tutorials mni
  • 【pytorch目标检测】FPN网络结构

    语义一般指的是图像每个像素点的类别归属 语义信息可以理解为与类别划分有关的信息 对网络前端通过非线性变换 对图像内容中纹理 几何颜色等信息表达 这种表达会使网络后端对类别归属做出正确的预测 低级语义信息 对浅层特征的表达 如颜色 几何 纹理
  • vue中的异步请求Axios(个人学习笔记五)

    目录 友情提醒 第一章 传统的jQuery方式获取数据 1 1 后端controller层代码 1 2 传统的jQuery获取数据 1 3 使用vue对象和jQuery获取异步数据 第二章 使用Axios获取数据 2 1 axios简介 2
  • 数据库技术基础--基本概念

    说在前面 本系列文章专注于软考备考复习内容梳理 文章内容是对教材中知识点和考点的提炼 备考过程中可以有针对的进行复习 减少阅读量 有的放矢 导航目录 一 数据库与数据库管理系统 1 数据库 2 硬件 3 软件 4 人员 二 DBMS的功能
  • Android开发 - 掌握ConstraintLayout(六)链条(Chains)

    本文我们介绍链条 Chains 使用它可以将多个View连接起来 互相约束 可以创建横向的链条 也可以创建纵向的链条 我们以横向的链条举例 我们先创建三个按钮 我们选中三个按钮后在上面点右键创建链条 创建后我们发现这三个View平均分布地排
  • Flutter中神奇的Builder组件

    经常遇到of这样的方法 却怎么都不可用 google之后找到了正确答案 原答案地址 https stackoverflow com questions 52502498 get current tab of defaulttabcontro
  • WPS以及它的两种方式PIN与PBC的理解

    WPS Wi Fi Protected Setup PBC Push ButtonConfiguration 这个是不需要密码的方式 PIN Personal Information Number 这个是要用密码的方式通常用在电子设备的互通
  • vue2 使用 Sortable 库进行拖拽操作

    一 vue 项目使用 文档地址 https www itxst com sortablejs neuinffi html 1 安装依赖 npm i S vuedraggable 2 vue 文件引入组件 import draggable f