Vue2点击事件为什么要点击两次才生效?

有一个button,效果是点击后出现日期选择控件,可是为啥我需要点击两次button才能出来日期控件呢?求大神解疑。。控件是jquery的datetimepicker时间控件

下面是官方手册里那个列表渲染的例子我改了一下

HTML:

<div id="todo-list-example">
          <input
            v-model="newTodoText"
            v-on:keyup.enter="addNewTodo"
            placeholder="Add a todo"
          >
          <ul>
            <li
              is="todo-item"
              v-for="(todo, index) in todos"
              v-bind:title="todo"
            ></li>
          </ul>
        </div>

JS:

Vue.component('todo-item', {
      template: '\
        <li>\
          {{ title }}\
          <button v-on:click="selectDate($event)">X</button>\
        </li>\
      ',
      props: ['title'],
      methods: {
        selectDate: function(e){
            // alert(111);如果换成alert点一次即能生效
            this.$emit($(e.target).datetimepicker());
        }
      },
    });
    new Vue({
      el: '#todo-list-example',
      data: {
        newTodoText: '',
        todos: [
          'Do the dishes',
          'Take out the trash',
          'Mow the lawn'
        ]
      },
      methods: {
        addNewTodo: function () {
          this.todos.push(this.newTodoText)
          this.newTodoText = ''
        }
      }
    });

给我的感觉是点击第一次在初始化,点击第二次才生效?怎么一次生效呢?

回答:

先谢过各位热心大神的回答…给了我很多思路,然而并没解决我的问题

这个问题我自己解决了,昨天才开始看Vue,新人一枚,谈谈我的思路。
首先感谢各位大神的热心解答。
一开始出现这个问题的时候,我在想是不是不能像过去写Jquery一样直接在<script></script>中绑定该控件?

$(document).on('click','#datetimepicker',function(){
    ....
})

难道像上面这样是绑不上的?于是我就在Vue实例中写了一个selectDate方法,点击按钮即触发它,然后再执行绑定。

selectDate: function(){
    $(document).on('click','#datetimepicker',function(){
        ...
    })
}

用这种方式的确能实现了,点击该元素后出现了日期控件。可是问题来了,怎么还需要点击两次?这谁受得了,不知道的还以为点了没反应呢。于是开始各种找问题,上百度搜了个遍,又来segament提问。

无奈开始找bug,怀疑是不是jquery和vue不兼容啊,然后把vue引用删了,的确好使。。。这就尴尬了,看来是Vue影响了控件的正常使用,可我还想用Vue啊,那只能继续翻Vue手册了。

然后猜想有可能是我点击后控件才开始初始化,所以点击第二次才生效?我一直确信应该是这么个情况,所以我就研究在哪里能提前把它初始化了或者说与元素绑定了。
于是看到了Vue的生命周期,Created、Updated、Mounted,全试了一个遍,发现的确是生命周期的问题,但只有Updated有效果,在Updated中绑定元素的话点击一次即可生效,到这里已经解决了我的问题,但是!Updated是数据有任何变化时候都会更新,也就是说假设打十个字,里面的函数会执行10次(可以console.log(123)看一下,确实执行了10遍),官方在手册中也提及了注意事项:

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。

对于我这个小网页来说对性能其实影响不大,但这肯定不是我想要的结果。所以我继续看看Vue手册中还有没有类似我这种情况的案例。
Updated 不行,我又想到了$on和$emit,是Vue自带的事件监听和执行方法,试了一下,效果和之前selecDate方法的效果是一样的没卵用。

这问题已经困扰我两天了,想到最后,觉得这个问题归根到底还是和DOM的出现时间点也就是Vue的生命周期有关系,不管Vue怎么处理DOM,肯定是datetimepicker一定要挂载到DOM出现后才能生效,还是翻文档,偶然间看到生命周期里还有一个$nextTick方法。

用法参考Vue异步更新队列,它是这么说的:

将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

简单理解就是DOM更新完后执行回调,于是我调用这个方法,然后在这个回调里执行datetimepicker,由于DOM已经被加载到了网页,所以也不需要绑定了,直接执行即可,果然得到了预期的效果。

事后我觉得费这么大劲虽然解决了这个问题,但是我的思路应该还是不对,起码和Vue数据驱动、虚拟DOM的思想不契合,到现在我还没转变过来,日后等转变了再来谈谈这个问题吧。

回答:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link href="http://cdn.bootcss.com/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.min.css" rel="stylesheet">
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="i in 3">
                <button v-datetimepicker @time-change="change($event, i)">show</button>
            </li>
        </ul>
    </div>

    <script src="http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script src="http://cdn.bootcss.com/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.full.min.js"></script>

    <script src="http://cdn.bootcss.com/vue/2.1.0/vue.min.js"></script>

    <script>
        Vue.directive('datetimepicker', {
            bind: function (el) {
                $(el).datetimepicker({
                    onChangeDateTime: function (dp, $input) {
                        el.dispatchEvent(new CustomEvent("time-change", { detail: $input.val() }))
                    }
                })
            }
        })

        new Vue({
            el: '#app',
            methods: {
                change(e, i) {
                    console.log(e.detail, i)
                }
            }
        })
    </script>
</body>
</html>

回答:

$(e.target).datetimepicker() 这个函数的确是在初始化,可以先初始化好,只控制是不是显示。

回答:

建议使用其他 日期选择 组件,如 element UI 库中的 日期选项 组件。

如果要在这里使用 jQuery 的插件,需要在 created 钩子里进行插件的初始化。

回答:

我以前遇到过类似的问题,但是我的情况是,将button给个type=”button”就好了,如果是submit就会导致这样的情况。虽然解决了,但是还是不知道原因。

暂无评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注