官方文檔:

官方也說明了,v-model只不過是一個語法糖而已,真正的實現靠的還是
1. v-bind : 綁定響應式數據
2. 觸發 input 事件 並傳遞數據 (核心和重點)
大體就是:
監聽原生組件的事件, 當獲取到原生組件的值后把值通過調用 $emit('input' ,data) 方法去觸發 input事件
demo:
父組件代碼:
<template> <div class="hello"> <button @click="ifShow=!ifShow">點擊顯示</button> <show-alert v-model="ifShow"></show-alert> </div> </template> <script> import showAlert from './showAlert.vue' export default { name: 'HelloWorld', components:{ showAlert, }, data () { return { ifShow:false, } } } </script>
子組件代碼:
<template> <div id="showAlert" :value="value" v-if="ifValue"> <div>showAlert 內容</div> <button class="close" @click="ifValue=false">關閉</button> </div> </template> <script> export default{ props:{ value:{ type:Boolean, default:false, } }, data:function(){ return{ ifValue:false, } }, watch:{ value(bool){ this.ifValue=bool; console.log('bool='+ bool); }, ifValue(val){ /*使用了v-model的組件會自動監聽 input 事件, * 並把這個input事件所攜帶的值 傳遞給v-model所綁定的屬性, * 這樣組件內部的值就給到了父組件了 */ this.$emit('input',val);//傳值給父組件, 讓父組件監聽到這個變化 } }, } </script> <style scoped> .close{ background:red; color:white; } </style>
實現效果:

點擊顯示按鈕以后:

前提: this.$emit('input',data);
點擊子組件關閉按鈕后:

如果未加this.$emit('input',data);
點擊子組件關閉按鈕后:

如果未通過$emit把值傳到父組件, 則父組件監聽不到子組件的變化.
====================================================================
封裝一個可復用的彈窗組件
<!-- 彈出窗口組件, 調用方法: 父組件import 當前vue文件, 在對應的components中注冊即可使用, 注意: 需要在父組件給一個boolean的屬性 通過v-model的形式關聯即可 其他屬性看下方注釋, params(父組件調用 標簽屬性): title-info 彈出框顯示文字 left-button 左邊按鈕文字 right-button 右邊按鈕文字 left-click 左邊按鈕點擊回調函數 right-click 右邊按鈕點擊回調函數 中間部分可以從父元素自定義設置通過slot放入 例子: <show-model> <p slot="reference">111</p> </show-model> 例子: <show-model v-model="flag" title-info="優惠碼輸入錯誤,請重試" left-button="取消" right-button="確定" @left-click="left_button" @right-click="right_button"></show-model> **** watch中增加. 當彈出窗彈出時,阻止后面頁面可以滾動的問題 --> <template> <div class="model-wrapper" :value="value" v-if="ifValue"> <div class="mask" @click="close_click"></div> <div class="model-content"> <p v-if="titleInfo">{{titleInfo}}</p> <div class="button-group" v-if="leftButton || rightButton"> <div v-if="leftButton" @click="left_click">{{leftButton}}</div> <div v-if="rightButton" @click="right_click">{{rightButton}}</div> </div> </div> </div> </template> <script> export default{ props:{ value:{ type:Boolean, default:false }, titleInfo:{ type:String, default:'' }, leftButton:{ type:String }, rightButton:{ type:String } }, data:function(){ return { ifValue:false, } }, methods:{ close_click:function(){ this.$emit('close-click'); }, left_click:function(){ this.$emit('left-click'); }, right_click:function(){ this.$emit('right-click'); } }, watch:{ value(bool){ this.ifValue=bool; }, ifValue(val){ this.$emit('input',val); } } } </script> <style scoped> .model-wrapper{ width:100%; height:100%; position:fixed; top:0; left:0; z-index:999; } .mask{ width:100%; height:100%; position:absolute; left:0; top:0; z-index:1; background-color:rgba(0,0,0,0.5); } .model-content{ width:80%; background:white; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:10; } .button-group{ margin-top:40px; display:flex; padding:0 10px 10px; } .button-group div{ flex:1; height:40px; line-height:40px; box-sizing:border-box; cursor:pointer; } .button-group div:first-child{ background:#000; color:#fff; } .button-group div:last-child{ border:1px solid gray; } </style>
在首頁調用
<button @click="showModel">點擊顯示彈窗</button>
<show-model v-model="ifShowModel" titleInfo="嘿嘿嘿" leftButton="確定" rightButton="取消" @close-click="close_click" @left-click="left_click" @right-click="right_click" ></show-model>
showModel:function(){ this.ifShowModel=true; }, close_click:function(){ this.ifShowModel=false; }, left_click:function(){ this.ifShowModel=false; }, right_click:function(){ this.ifShowModel=false; }

