通过v-model控制组件的显示隐藏

之前在用ivew组件库的时候,就一直觉得很好奇,那个组件库的modal是怎么使用v-model来控制显示隐藏的。我印象中v-model是用于view和modal之间的数据双向绑定,官网也有资料:

通过v-model控制组件的显示隐藏

 

官网对于input,select等标签都有解释,但是却没有div。一般我们在自定义组件的时候,最外层都是套div,控制显示隐藏的时候,就通过父组件传入属性的方式来用v-if去控制。但是iview的组件却没有通过属性,而是直接传递v-model去控制,这就很有意思了。那如果我们自己也想通过v-model去控制div的显示隐藏呢?我没有去看过iview组件的源码,不知道他们是怎么写的,不过有一种办法可以达到那个效果。或许可以尝试一下。

Modal.vue

 1 <template>
 2   <div class="modal-container" v-if="showModal">
 3     <p>我就是一段文字而已。</p>
 4     <div class="bottom-btn">
 5       <button>确定</button>
 6       <button @click="clickCancel">取消</button>
 7     </div>
 8   </div>
 9 </template>
10 
11 <script>
12 export default {
13   props: {
14     value: {
15       default: true,
16       type: Boolean
17     }
18   },
19   watch: {
20     value(val) {
21       this.showModal = val;
22     },
23     showModal(val) {
24       this.$emit("input", val);
25     }
26   },
27   data() {
28     return {
29       showModal: false
30     };
31   },
32   methods: {
33     clickCancel() {
34       this.showModal = false;
35     }
36   },
37   mounted() {
38   }
39 };
40 </script>
41 
42 <style scoped>
43 .modal-container {
44   background: #eee;
45   width: 300px;
46   height: 240px;
47   position: absolute;
48   top: 0;
49   left: 0;
50   right: 0;
51   bottom: 0;
52   margin: auto;
53   border-radius: 10px;
54 }
55 .bottom-btn {
56   display: flex;
57   align-items: flex-end;
58   height: 70%;
59   justify-content: center;
60 }
61 .bottom-btn button {
62   outline: none;
63   border: none;
64   width: 70px;
65   height: 40px;
66   line-height: 40px;
67   text-align: center;
68 }
69 </style>

先建了一个Modal的组件,定义一个变量showModal用于控制该组件是否显示,这个组件内部接收一个value的属性,它是一个布尔值,主要就是通过这个外部的值来判断显示隐藏,但是vue不建议直接修改父组件传进来的数据,因此把value的值赋值给showModal。很重要的一步就是侦听器这里,监听了value值也监听了组件内部的showModal,外部传入value时,值改变会触发这个侦听器,然后在这里把值给showModal,showModal又绑定到了v-if上。而在点击取消按钮时,showModal发生改变会被监听到,所以发送了input事件,但是这个input事件我感觉并没有发送给父组件,而是直接触发的div自身的input事件,一般通过$emit去发送事件时,父组件是需要去实现这个事件的,而在这个例子很明显父组件并没有去实现这个input,但是父组件的值却被修改了,那它是怎么做到的呢。其实看到这里在结合官网的解释或许基本上就能明白了:“v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理”。

因为div本身就有input事件,只不过用的比较少。把div标签的contenteditable属性设置为true就可以把div变成输入框,既然如此那它当然就具备输入框的功能和事件了。所以这里之所以不需要父组件去实现子组件发送的事件,感觉上是因为发送的这个事件直接触发了它本身的input,触发之后vue自动的把input事件所传递的值赋值给了v-model所绑定的值,然后Modal组件监听到value改变为了false,赋值给了showModal。看起来似乎有点绕,但感觉大致上是这样。

HelloWorld.vue:

<template>
  <div>
    <button @click="clickOpen">打开弹出框</button>
    <Modal v-model="openModal"></Modal>
  </div>
</template>

<script>
import Modal from "./Modal";
export default {
  name: "HelloWorld",
  components:{
    Modal
  },
  data() {
    return {
      openModal:false
    };
  },
  methods: {
    inputContent(val){
      console.log(val)
    },
    clickOpen(){
      this.openModal = true
    }
  }
};
</script>

这样就可以不用属性的方式,而是通过v-model的方式去控制div的隐藏和显示了。其实就算不用v-model也可以直接实现,那就是通过属性也一样,让子组件同样的通过该属性绑定v-if,因为Modal内部本质上也是在使用v-if控制。其实也没有什么区别。我个人仅仅只是好奇iview的实现方式而已。当然了,毕竟没看过iview源码,他们是不是这么做的不太清楚,但这只是一种方式而已。不用太在意。多了解一点总没坏处。

 

上一篇:vue组件中,iview的modal组件爬坑--modal的显示与否应该是使用v-show


下一篇:AntD Modal.confirm 确认弹出框用法