vue2组件之select2调用的示例代码


Posted in Javascript onOctober 12, 2017

目前,项目中使用了纯前端的静态项目+RESTFul接口的模式。为了更好的对数据进行操作,前端使用了vue2的mvvm功能,但是由于不是单页面应用,所以,并没有涉及到其它的如vue-route等功能,也未使用webpack等编译功能,所以,也没有使用.vue文件功能。这时候,如果用到控件,则多数从原jquery的组件中选择。

select下拉搜索选择

这次的需求调研与设计是原来做winform开发的同事,由于用惯了devexpress这个控件库,所以,对于searchlookupeditor这个控件情有独钟,所以,在设计的时候,许多地方都用到。

最初实现

最初,我使用了select2绑定select标签,设定其change事件 ,在事件中修改对应的vue的data值,同时,在vue中设定watch``data中被绑定的属性,属性值发生变化,则修改对应的dom的val,然后再触发select2的change事件。当然,这种对应关系,我在select标签上放了一个data-vuep来保存其与vue属性的对应关系,并放在全局的select2vue和dom2vue中。

//mounted中的部分代码
            select2vue = {};
          $("select").each(function (index, item) {
            var s2 = $(item).select2({
              language: "zh-CN", //设置 提示语言
              width: "100%", //设置下拉框的宽度
              theme: "classic",
              placeholder: "请选择"
            }).on("change", function (e) {
              console.log(e);
              var v = $(e.target).val();
              var p = $(e.target).attr("data-vuep");
              eval("vue_cust_busi." + p + "='" + v + "';");
              //$(e.target).find("option").attr("selected",false);
              //$(e.target).find("option[value='"+v+"']").attr("selected",true);
            });

            var p = $(item).attr("data-vuep");
            select2vue[p] = s2;
            dom2vue[p] = item;
          });
          setTimeout(function(){
            vue_cust_busi.editor.ID_CUST="3";
            vue_cust_busi.editor.NAME_CUST="*有限责任公司";
            console.log("修改");
          },10,null);


//watch中的部分代码
          "temp.P1": function (val) {
            fire(arguments.callee.name.toString(), val);

          },
//通用函数

    function fire(p, val) {
      $(dom2vue[p]).val(val);
      select2vue[p].trigger("change");
    }

//html

                        <select data-vuep="editor.P1" class="form-control "> 
                            <option value="" ></option>  
                            <option v-for="yearOpt in yearOpts" v-bind:value="yearOpt">{{yearOpt}}</option> 
                        </select>

为什么要用一个data-vuep来将数据与vue的属性关联呢,因为我发现,select2初始化了这个select标签之后,修改这个标签的值无法触发修改vue对应的v-model的属性。所以,只能用这个方法。
 最终形成的结果是:

select2到vue.editor.P1:
1.select2被选择某一项,触发其change事件。
2.select2的change事件修改vue.editor.P1的值。
3.vue.editor.P1的值被修改,触发watch,watch又引发select2的change事件,但是,select2内部监控到选择和之前的一致,所以,不再执行change事件的委托。

上面这种流程一定程度是实现了数据的双向绑定,但是,非常复杂。在后续的使用中发现,在mounted中无法为select2默认值,必须在mounted中调用setTimeout生成一个定时执行的事件来执行数据绑定操作,才会触发上述流程,达到设定触始值的效果。

使用vue指令

经过一番挣扎,觉得上面这种方式还是不行。

上述方案不好的原因如下:

1.vue事件中的代码操作了dom,这样,在生命周期上可能会出现问题,特别是后来使用了setTimeout之后,生命周期变得更加不可控制。
2.每增加一个select组件,都需要增加 html标签、watch,而且,html 标签和watch既不是传统的写法,也不是vue的写法,而是发明了一种新的东西,这破坏了开发体验。
3.维护性比较差,当想删除一个select的时候,必须要去watch里面去找与html中data-vuep相等的属性监控方法,并将其删除掉。
4.兼容性不好,本方案选择将页面所有的select全部用select2初始化了一次,使得不论是否需要的,都会被影响;其次,如果不统一初始化,那么又多出了在mounted中为每一个select写初始化代码的工作,同时,也要为每个select取一个id。

为了解决这个问题,我又找到了最初看到的那个vue使用指令和select2的整合的例子。网上有好多,我不知道版权是谁的,姑且上我最先看到的那个吧。https://3water.com/article/125654.htm

原文中的代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>vue select2 封装</title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="external nofollow" rel="stylesheet" />
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
  <style type="text/css">
    .content{
      text-align: center;
      padding:50px;
    }
    .content *{
      text-align: left;
    }
    .select{
      width: 350px;
    }
  </style>
</head>
<body>
  <div class="content" id="vue-example">
    <select class="select" v-select2='options' v-model="selectValue"></select>
    <br/>
    <span>结果:{{ selectValue }}</span>
  </div>
</body>
<script type="text/javascript">
  Vue.directive('select2', {
   inserted: function (el, binding, vnode) {
     let options = binding.value || {};
 
    $(el).select2(options).on("select2:select", (e) => {
     // v-model looks for
     // - an event named "change"
     // - a value with property path "$event.target.value"
       el.dispatchEvent(new Event('change', { target: e.target })); //说好的双向绑定,竟然不安套路
    });
   },
   update: function(el, binding, vnode) {
    $(el).trigger("change");
   }
  });
 
  var vueApp = new Vue({
   el: "#vue-example",
   data: {
    selectValue: '你还没有选值',
    options: {
      data: [
          { id: 0, text: 'enhancement' },
        { id: 1, text: 'bug' },
        { id: 2, text: 'duplicate' },
        { id: 3, text: 'invalid' },
        { id: 4, text: 'wontfix' }
      ]
    }
   }
  });
</script>
</html>

作者也说了,对vue2.x的双向绑定机制不了解,希望路过的大神帮帮忙。

我不是vue2的大神,甚至连新手都不算,只能说是初学者。我对代码进行了调整,当然,也是操作了dom,但是由于封装在指令里面了,使用人员不需要再次操作,不涉及到开发人员操作dom的情况,我还是可以接受的。

Vue.directive('select2', {
      inserted: function (el, binding, vnode) {
        let options = binding.value || {};

        $(el).select2(options).on("select2:select", (e) => {
          // v-model looks for
          // - an event named "change"
          // - a value with property path "$event.target.value"
          el.dispatchEvent(new Event('change', { target: e.target })); //说好的双向绑定,竟然不安套路
          console.log("fire change in insert");
        });
      },
      update: function (el, binding, vnode) {
        for (var i = 0; i < vnode.data.directives.length; i++) {
          if (vnode.data.directives[i].name == "model") {
            $(el).val(vnode.data.directives[i].value);
            console.log("new value in update:"+vnode.data.directives[i].value);
          }
        }
        $(el).trigger("change");
        console.log("fire change in update");
      }
    });

//html代码

<select v-select2="" v-model="editor.P1" required="required" class="form-control ">
 <option value=""></option>
 <option v-for="item in codes" v-bind:value="item.NAME">{{item.NAME}}</option>
</select>

经过好几天的研究,终于我发现在作者原来的代码的update中,加入修改el的val值,然后再触发select2的change事件,就可以了。而在使用方面,只需要给加一个v-select2即可,v-model以及option的配置都依照vue2的推荐方式,原封不动。之所以加了一个空的option是因为如果不加,默认select2是选择第一个选项的,但是,由于未知原因,与vue.editor.P1并不同步。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript 面向对象之重载
May 04 Javascript
javascript实现倒计时(精确到秒)
Jun 26 Javascript
javascript实现仿百度图片的瀑布流加载效果
Apr 20 Javascript
js实现界面向原生界面发消息并跳转功能
Nov 22 Javascript
jQuery Easyui datagrid editor为combobox时指定数据源实例
Dec 19 Javascript
JS回调函数简单用法示例
Feb 09 Javascript
利用js查找数组中指定元素并返回该元素的所有索引示例
Mar 29 Javascript
详解angularjs中的隔离作用域理解以及绑定策略
May 31 Javascript
BootStrap模态框不垂直居中的解决方法
Oct 19 Javascript
详解JS模块导入导出
Dec 20 Javascript
简述vue状态管理模式之vuex
Aug 29 Javascript
学习node.js 断言的使用详解
Mar 18 Javascript
vue2.x select2 指令封装详解
Oct 12 #Javascript
一个简易时钟效果js实现代码
Mar 25 #Javascript
微信小程序实现页面跳转传值的方法
Oct 12 #Javascript
微信小程序 页面滑动事件的实例详解
Oct 12 #Javascript
微信小程序 动画的简单实例
Oct 12 #Javascript
node通过npm写一个cli命令行工具
Oct 12 #Javascript
JS实现自定义状态栏动画文字效果示例
Oct 12 #Javascript
You might like
PHP 配置文件中open_basedir选项作用
2009/07/19 PHP
PHP错误Allowed memory size of 67108864 bytes exhausted的3种解决办法
2014/07/28 PHP
[原创]CI(CodeIgniter)简单统计访问人数实现方法
2016/01/19 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
javascript CSS画图之基础篇
2009/07/29 Javascript
js压缩工具 yuicompressor 使用教程
2010/03/31 Javascript
alert中断settimeout计时功能
2013/07/26 Javascript
js清理Word格式示例代码
2014/02/13 Javascript
Javascript异步编程模型Promise模式详细介绍
2014/05/08 Javascript
javascript函数式编程实例分析
2015/04/25 Javascript
jQuery实现TAB风格的全国省份城市滑动切换效果代码
2015/08/24 Javascript
非常棒的jQuery图片轮播效果
2016/04/17 Javascript
jQuery选择器及jquery案例详解(必看)
2016/05/20 Javascript
bootstrap下拉列表与输入框组结合的样式调整
2016/10/08 Javascript
简单实现JS倒计时效果
2016/12/23 Javascript
通过vue提供的keep-alive减少对服务器的请求次数
2018/04/01 Javascript
redux中间件之redux-thunk的具体使用
2018/04/17 Javascript
详解vue移动端项目的适配(以mint-ui为例)
2018/08/17 Javascript
js仿淘宝放大镜效果
2020/12/28 Javascript
[28:42]Ti4正赛VG vs NEWBEE1
2014/07/19 DOTA
[00:30]明星选手化身超级英雄!2018DOTA2亚洲邀请赛全明星赛来临!
2018/04/06 DOTA
图文详解WinPE下安装Python
2016/05/17 Python
python安装numpy&amp;安装matplotlib&amp; scipy的教程
2017/11/02 Python
Django错误:TypeError at / 'bool' object is not callable解决
2019/08/16 Python
python 表格打印代码实例解析
2019/10/12 Python
python多线程案例之多任务copy文件完整实例
2019/10/29 Python
使用python绘制二维图形示例
2019/11/22 Python
Python统计时间内的并发数代码实例
2019/12/28 Python
俄罗斯香水和化妆品购物网站:Л’Этуаль
2018/05/10 全球购物
高中微机老师自我鉴定
2014/02/16 职场文书
国际经济贸易专业自荐信
2014/06/13 职场文书
超搞笑婚前保证书
2015/05/08 职场文书
2015教师个人年度工作总结
2015/10/23 职场文书
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js
Python OpenCV实现图像模板匹配详解
2022/04/07 Python
微信小程序纯CSS实现无限弹幕滚动效果
2022/09/23 HTML / CSS