通過(guò)vue.extend實(shí)現(xiàn)消息提示彈框的方法記錄
前提回顧
在項(xiàng)目開(kāi)發(fā)中我們經(jīng)常使用的組件注冊(cè)分為兩種,一個(gè)是全局注冊(cè)和另一個(gè)是局部注冊(cè),假設(shè)我們的業(yè)務(wù)場(chǎng)景是用戶在瀏覽注冊(cè)頁(yè)面時(shí),點(diǎn)擊頁(yè)面中的注冊(cè)按鈕后,前端根據(jù)用戶的注冊(cè)信息先做一次簡(jiǎn)單的驗(yàn)證,并根據(jù)驗(yàn)證彈出一個(gè)對(duì)應(yīng)消息提示彈框
我們拿到這個(gè)需求后,便開(kāi)始著手準(zhǔn)備要通過(guò)局部注冊(cè)消息彈框組件的方法來(lái)實(shí)現(xiàn)這個(gè)場(chǎng)景,在通過(guò)局部注冊(cè)消息彈框組件的方法解決完這個(gè)需求后,自然是沾沾自喜,緊接著又迎來(lái)了一個(gè)需求,該需求是用戶在點(diǎn)擊該注冊(cè)按鈕時(shí),點(diǎn)擊幾次就要出現(xiàn)幾次這個(gè)消息彈框,你開(kāi)始犯了難,并思考難道我要在頁(yè)面中提前插入n個(gè)組件標(biāo)簽,不然我怎么知道用戶要點(diǎn)擊幾次注冊(cè)按鈕?
在你還沒(méi)有解決第二個(gè)需求的時(shí)候,又一個(gè)需求來(lái)了,第三個(gè)需求是不僅僅是注冊(cè)頁(yè)面需要用到這個(gè)消息彈框組件,在其他多個(gè)頁(yè)面中也需要用到這個(gè)消息彈框組件。
基于上述的業(yè)務(wù)需求,我們可以通過(guò)vue.extend編程式的使用組件,從而實(shí)現(xiàn)功能性的動(dòng)態(tài)的消息提示彈框
局部注冊(cè)消息彈框組件
先通過(guò)局部注冊(cè)的方法來(lái)實(shí)現(xiàn)消息彈框組件
效果圖如下:
構(gòu)造目錄如下:
'src/main.js'文件的代碼:
import Vue from 'vue' import App from './App.vue' //全局引入樣式文件 import './assets/css.css'; Vue.config.productionTip = false new Vue({ render: h => h(App) }).$mount('#app')
'src/bus/bus.js'文件的代碼:
import vue from 'vue'; var bus=new vue() export default bus;
'src/App.vue'文件的代碼:
<template> <div id="app"> <button @click="handleShowMessage">點(diǎn)擊出現(xiàn)彈框</button> <TMessage :offsetTop='50'></TMessage> <TMessage :offsetTop='100'></TMessage> <TMessage :offsetTop='150'></TMessage> <!-- 我是不是得在這里埋下幾萬(wàn)個(gè)消息彈框組件??? --> </div> </template> <script> import TMessage from './components/TMessage/TMessage.vue'; import bus from './bus/bus'; export default { name:'app', data() { return { } }, components: { TMessage, }, methods: { handleShowMessage(){ //打印查看消息彈框的組件對(duì)象 console.log(TMessage); //點(diǎn)擊按鈕后出現(xiàn)消息彈框 bus.$emit('showMessage') } }, } </script> <style> #app { display: flex; justify-content: center; } #app button{ margin-top: 250px; } </style>
'src/components/TMessage/TMessage.vue'文件的代碼:
<template> <transition name="message-fade"> <div :class="[ 'message', 'message-' + type, center ? 'is-center' : '' ]" :style="{top: offset + 'px'}" v-if="!closed" > <p class="message-content">提示信息:{{message}}</p> <i class="icon icon-close"></i> </div> </transition> </template> <script> export default { name: 'TMessage', data() { return { message: '這是默認(rèn)信息', //彈框的提示內(nèi)容 type: 'success', //彈框的樣式 success、warning、error center: true, //彈框是否居中顯示 offset: 20, //彈框默認(rèn)的偏移量 closed: true, //彈框默認(rèn)隱藏 通過(guò)v-if="!closed"控制 duration: 1000, //彈框消失的時(shí)間 timer: null, //準(zhǔn)備一個(gè)定時(shí)器 } }, mounted() { this.offset=this.offsetTop bus.$on('showMessage',()=>{ this.closed=false; this.timer = setTimeout(() => { //如果彈框是顯示狀態(tài)的話在duration后會(huì)變?yōu)殡[藏狀態(tài) if (!this.closed) { this.close(); } }, this.duration); }) }, props:['offsetTop'], methods: { close() { this.closed = true; } } } </script>
寫到這里,我們實(shí)現(xiàn)的效果為(動(dòng)圖如下):
'src/assets/css.css'文件的代碼:
/* 樣式重點(diǎn)解析: 1.'message' 2.'message-' + type: 2.1:message-success 2.2:message-warning 2.3:message-error 3.'is-center' //決定了彈框居中顯示 4.'message-fade-enter' //4和5決定了彈框的的過(guò)渡效果 5.'message-fade-leave-active' 6. .message { top:20px; //決定了彈框的偏移量 } */ .message { min-width: 380px; -webkit-box-sizing: border-box; box-sizing: border-box; border-radius: 4px; border-width: 1px; border-style: solid; border-color: #EBEEF5; position: fixed; left: 50%; top: 20px; z-index: 999999999; transform: translateX(-50%); background-color: #edf2fc; transition: opacity .3s, transform .4s, top .4s; overflow: hidden; padding: 15px 15px 15px 20px; display: flex; align-items: center } .message.is-center { -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center } .message p { margin: 0 } .message-info .message-content { color: #909399 } .message-success { background-color: #f0f9eb; border-color: #e1f3d8 } .message-success .message-content { color: #67C23A } .message-warning { background-color: #fdf6ec; border-color: #faecd8 } .message-warning .message-content { color: #E6A23C } .message-error { background-color: #fef0f0; border-color: #fde2e2 } .message-error .message-content { color: #F56C6C } .message-content { padding: 0; font-size: 14px; line-height: 1 } .message-content:focus { outline-width: 0 } .message .icon-close { position: absolute; top: 50%; right: 15px; -webkit-transform: translateY(-50%); transform: translateY(-50%); cursor: pointer; color: #C0C4CC; font-size: 16px } .message .icon-close:focus { outline-width: 0 } .message .icon-close:hover { color: #909399 } .message-fade-enter, .message-fade-leave-active { opacity: 0; transform: translate(-50%, -100%) }
編程式的使用組件
上方在通過(guò)局部注冊(cè)消息彈框組件時(shí)體現(xiàn)的局限性:靈活性低、可復(fù)用性低、代碼觀感較差
緊接著我們就要使用vue.extend來(lái)實(shí)現(xiàn)消息提示彈框,做到編程式的使用組件
該構(gòu)造目錄為:
'src/App.vue'文件的代碼:
<template> <div id="app"> <button @click="handleShowMessage">點(diǎn)擊出現(xiàn)彈框</button> </div> </template> <script> import Message from './components/TMessage/TMessage.js'; export default { name:'app', data() { return { } }, methods: { handleShowMessage(){ /** * 每點(diǎn)擊一次按鈕就調(diào)用一次該工廠函數(shù) * 每調(diào)用一次該工廠函數(shù)就創(chuàng)建一個(gè)彈框組件對(duì)象 */ return Message('我好帥啊我好帥啊我好帥啊') } }, } </script> <style> #app { display: flex; justify-content: center; } #app button{ margin-top: 250px; } </style>
'src/components/TMessage/TMessage.vue'文件的代碼:
<template> <transition name="message-fade"> <div :class="[ 'message', 'message-' + type, center ? 'is-center' : '' ]" :style="{top: offset + 'px'}" v-if="!closed" > <p class="message-content">提示信息:{{message}}</p> <i class="icon icon-close"></i> </div> </transition> </template> <script> export default { name: 'TMessage', data() { return { message: '這是默認(rèn)信息', //彈框的提示內(nèi)容 type: 'success', //彈框的樣式 success、warning、error center: true, //彈框是否居中顯示 offset: 20, //彈框默認(rèn)的偏移量 closed: false, //彈框默認(rèn)隱藏 通過(guò)v-if="!closed"控制 duration: 1000, //彈框消失的時(shí)間 timer: null, //準(zhǔn)備一個(gè)定時(shí)器 } }, mounted() { /*為了方便演示先不讓彈框消失 this.timer = setTimeout(() => { //在規(guī)定的this.duration后該消息彈框消失 if (!this.closed) { this.close(); } }, this.duration); */ }, methods: { close() { this.closed = true; } } } </script>
'src/components/TMessage/TMessage.js'文件的代碼:
import Vue from 'vue'; import TMessage from "./TMessage.vue"; function Message(data) { data = data || {}; if (typeof data === 'string') { data = { message: data } } const TMessageClass = Vue.extend(TMessage); //得到的是一個(gè)組件對(duì)象VueComponent實(shí)例 //new TMessageClass接收的是一個(gè)包含組件選項(xiàng)的對(duì)象 覆蓋 let instance = new TMessageClass({ data }); instance.$mount(); console.log(instance.$el,'現(xiàn)在才可以訪問(wèn)$el'); /* instance.$el的打印結(jié)果如下: <div class="message message-success is-center" style="top: 20px;"> <p class="message-content">提示信息:我好帥啊我好帥啊我好帥啊</p> <i class="icon icon-close"></i> </div> */ document.body.appendChild(instance.$el); } export default Message
寫到這里,我們來(lái)看一下效果,如下圖:
解決消息彈框覆蓋問(wèn)題
我們已經(jīng)做到了每點(diǎn)擊一次按鈕就出現(xiàn)一個(gè)消息彈框組件,但是因?yàn)槎ㄎ坏膯?wèn)題出現(xiàn)了相互覆蓋,所以得再接著去'TMessage.js'文件中去完善邏輯:
//file:'src/components/TMessage/TMessage.js' /* 解決方法: 通過(guò)維護(hù)一個(gè)隊(duì)列來(lái)存儲(chǔ)每一個(gè)消息彈框組件對(duì)象 在每一次生成消息彈框組件時(shí)都需要重新計(jì)算其top值 通過(guò)該隊(duì)列來(lái)計(jì)算上一個(gè)消息彈框組件對(duì)象的top值 */ import Vue from 'vue'; import TMessage from "./TMessage.vue"; //裝有instance消息彈框組件對(duì)象的容器 let instances = []; function Message(data) { data = data || {}; if (typeof data === 'string') { data = { message: data } } data.onClose = function() { console.log('onClose'); // 每消失一個(gè)消息彈框就會(huì)觸發(fā)一個(gè)onClose //instance是消息彈框組件的實(shí)例對(duì)象即VueComponent console.log(instance,'instance'); //每消失一個(gè)就得把在instances容器中對(duì)應(yīng)的該組件對(duì)象給刪除掉 Message.close(instance); }; const TMessageClass = Vue.extend(TMessage); let instance = new TMessageClass({ data }); instance.$mount(); document.body.appendChild(instance.$el); //如果data數(shù)據(jù)中有設(shè)置偏移量則使用該偏移量 //否則使用默認(rèn)的偏移量值20 let offset = data.offset || 20; //規(guī)定每一個(gè)消息彈框的間隔 //這里直接使用offset值做為間隔 let offsetTop = offset; /**思路如下: * let offsetTop=20; * [].forEach(()=>{offsetTop+=10}); * console.log(offsetTop) //還是20 * * [{a:'1'}].forEach(()=>{offsetTop+=10}); * console.log(offsetTop) //才是30 */ /*這里是在循環(huán)之后才去push 因?yàn)樯傻牡谝粋€(gè)消息彈框是不需要計(jì)算offsetTop的 生成的第一個(gè)消息彈框直接使用offset值即可 */ //從第一個(gè)起instances里有值了(組件對(duì)象)以后再去循環(huán)計(jì)算offsetTop值 instances.forEach( item => { //根據(jù)上一個(gè)計(jì)算的offsetTop+自身的高度+規(guī)定的間隔 offsetTop += item.$el.offsetHeight + offset; }); //當(dāng)前生成的消息彈框的高度為offsetTop //offsetTop是根據(jù)上一個(gè)生成的消息彈框的三個(gè)值計(jì)算得到的 //instances容器中第0個(gè)是不需要參與計(jì)算的即采用默認(rèn)的offset值 instance.$el.style.top = offsetTop + 'px'; instances.push(instance); } Message.close = function(instance) { //每消失一個(gè)就得把在instances容器中對(duì)應(yīng)的該組件對(duì)象給刪除掉 instances = instances.filter( item => item !== instance ); }; export default Message
'src/components/TMessage/TMessage.vue'文件的代碼:
//file:'src/components/TMessage/TMessage.vue' <template> <transition name="message-fade"> <div :class="[ 'message', 'message-' + type, center ? 'is-center' : '' ]" :style="{top: offset + 'px'}" v-if="!closed" > <p class="message-content">提示信息:{{message}}</p> <i class="icon icon-close"></i> </div> </transition> </template> <script> export default { name: 'TMessage', data() { return { message: '這是默認(rèn)信息', //彈框的提示內(nèi)容 type: 'success', //彈框的樣式 success、warning、error center: true, //彈框是否居中顯示 offset: 20, //彈框默認(rèn)的偏移量 closed: false, //彈框默認(rèn)隱藏 通過(guò)v-if="!closed"控制 duration: 1000, //彈框消失的時(shí)間 timer: null, //準(zhǔn)備一個(gè)定時(shí)器, onClose: null //擴(kuò)充一個(gè)功能 彈框消失后觸發(fā) } }, mounted() { //在規(guī)定的this.duration后該消息彈框消失 //消息框消失后會(huì)觸發(fā)this.close()函數(shù)方法 this.timer = setTimeout(() => { if (!this.closed) { this.close(); } }, this.duration); }, methods: { close() { this.closed = true; //如果該組件可以接收到this.onClose方法則調(diào)用該方法 //該方法是在該消息彈框消失的時(shí)候被觸發(fā) if (typeof this.onClose === 'function') { this.onClose(); } } } } </script>
寫到這里,我們來(lái)看一下效果,如下圖:
優(yōu)化消息彈框消失的效果
我們可以進(jìn)一步的優(yōu)化消息彈框消失的效果,效果圖如下:
'src/components/TMessage/TMessage.vue'文件的代碼:
<template> <transition name="message-fade"> <div :class="[ 'message', 'message-' + type, center ? 'is-center' : '' ]" :style="{top: offset + 'px'}" v-if="!closed" > <p class="message-content">提示信息:{{message}}</p> <i class="icon icon-close"></i> </div> </transition> </template> <script> export default { name: 'TMessage', data() { return { message: '這是默認(rèn)信息', type: 'success', center: true, offset: 20, closed: false, duration: 1000, timer: null, onClose: null //擴(kuò)充一個(gè)功能 彈框消失后觸發(fā) } }, mounted() { this.timer = setTimeout(() => { if (!this.closed) { this.close(); } }, this.duration); }, methods: { close() { this.closed = true; //當(dāng)彈框消失時(shí)會(huì)調(diào)用this.onClose()該函數(shù)方法 if (typeof this.onClose === 'function') { this.onClose(); } } } } </script>
'src/components/TMessage/TMessage.js'文件的代碼:
import Vue from 'vue'; import TMessage from "./TMessage.vue"; //裝有instance的容器 let instances = []; function Message(data) { data = data || {}; if (typeof data === 'string') { data = { message: data } } const TMessageClass = Vue.extend(TMessage); let instance = new TMessageClass({ data }); instance.$mount(); document.body.appendChild(instance.$el); data.onClose = function() { console.log('onClose'); // 每消失一個(gè)彈框就會(huì)觸發(fā)一個(gè)onClose方法 Message.close(instance); }; //如果data數(shù)據(jù)中有設(shè)置偏移量則使用該偏移量 //否則使用默認(rèn)的偏移量20 let offset = data.offset || 20; //規(guī)定每一個(gè)消息彈框的間隔 let offsetTop = offset; instances.forEach( item => { //上一個(gè)實(shí)例對(duì)象的offsetTop+自身的高度+規(guī)定的間隔 offsetTop += item.$el.offsetHeight + offset; }); instance.$el.style.top = offsetTop + 'px'; instances.push(instance); } Message.close = function(instance) { /* 每次彈窗關(guān)閉都會(huì)調(diào)用一次這個(gè)函數(shù) * 獲取當(dāng)前這個(gè)instance的高度 * 把這個(gè)instance后面的所有實(shí)例的top減去這個(gè)高度,再減去偏移 * */ let removeHeight = instance.$el.offsetHeight + instance.offset; //把傳遞進(jìn)來(lái)的instance在容器instances中刪除 let index = instances.findIndex( item => item === instance ); instances = instances.filter( item => item !== instance ); //對(duì)應(yīng)的消息彈框消失后在該消息彈框后面的消息彈框會(huì)依次出現(xiàn)頂上來(lái)的效果 //原理是找到對(duì)應(yīng)的消息彈框在instances容器中的下標(biāo)位置 //通過(guò)循環(huán)改變對(duì)應(yīng)的消息彈框后面的所有消息彈框的高度 for (let i = index; i<instances.length; i++) { instances[i].$el.style.top = parseFloat(instances[i].$el.style.top) - removeHeight + 'px'; } }; export default Message
'src/App.vue'文件的代碼:
<template> <div id="app"> <button @click="handleShowMessage">點(diǎn)擊出現(xiàn)彈框</button> </div> </template> <script> import Message from './components/TMessage/TMessage.js'; export default { name:'app', data() { return { } }, methods: { handleShowMessage(){ /** * 調(diào)用一次就創(chuàng)建一個(gè)彈框組件對(duì)象 */ return Message('我好帥啊我好帥啊我好帥啊') } }, } </script> <style> #app { display: flex; justify-content: center; } #app button{ margin-top: 250px; } </style>
終極版實(shí)現(xiàn)版
我們?cè)谏戏?src/App.vue'文件中是通過(guò)引入TMessage.js后再通過(guò)Message()的方式調(diào)用使用該組件的,還可以將調(diào)用方式掛載到Vue全局上,來(lái)看看怎么操作:
'src/main.js'文件的代碼
import Vue from 'vue' import App from './App.vue' import './assets/css.css'; import Message from '../src/components/TMessage/TMessage'; Vue.config.productionTip = false //掛載到全局 Vue.prototype.$message = Message; new Vue({ render: h => h(App) }).$mount('#app')
'src/App.vue'文件的代碼
<template> <div id="app"> <button @click="handleShowMessage">點(diǎn)擊出現(xiàn)彈框</button> </div> </template> <script> export default { name:'app', data() { return { } }, methods: { handleShowMessage(){ this.$message.error('我好帥啊我好帥啊我好帥啊') this.$message.success('我好帥啊我好帥啊我好帥啊') this.$message.info('我好帥啊我好帥啊我好帥啊') this.$message.warning('我好帥啊我好帥啊我好帥啊') } }, } </script> <style> #app { display: flex; justify-content: center; } #app button{ margin-top: 250px; } </style>
'src/components/TMessage/TMessage.vue'文件的代碼:
<template> <transition name="message-fade"> <div :class="[ 'message', 'message-' + type, center ? 'is-center' : '' ]" :style="{top: offset + 'px'}" v-if="!closed" > <p class="message-content">提示信息:{{message}}</p> <i class="icon icon-close"></i> </div> </transition> </template> <script> export default { name: 'TMessage', data() { return { message: '這是默認(rèn)信息', type: 'success', center: true, offset: 20, closed: false, duration: 1000, timer: null, onClose: null //擴(kuò)充一個(gè)功能 彈框消失后觸發(fā) } }, mounted() { this.timer = setTimeout(() => { if (!this.closed) { this.close(); } }, this.duration); }, methods: { close() { this.closed = true; //當(dāng)彈框消失時(shí)會(huì)調(diào)用this.onClose()該函數(shù)方法 if (typeof this.onClose === 'function') { this.onClose(); } } } } </script>
'src/components/TMessage/TMessage.js'文件的代碼:
import Vue from 'vue'; import TMessage from "./TMessage.vue"; let instances = []; function Message(data) { data = data || {}; if (typeof data === 'string') { data = { message: data } } data.onClose = function() { console.log('onClose'); //instance是消息彈框組件的實(shí)例對(duì)象即VueComponent Message.close(instance); }; const TMessageClass = Vue.extend(TMessage); let instance = new TMessageClass({ data }); instance.$mount(); // console.log(instance.$el,'現(xiàn)在才可以訪問(wèn)$el'); document.body.appendChild(instance.$el); let offset = data.offset || 20; //規(guī)定每一個(gè)消息彈框的間隔 let offsetTop = offset; //第一個(gè)彈框是不需要計(jì)算偏移量的 //從第一個(gè)以后再去循環(huán) instances.forEach( item => { //上一個(gè)實(shí)例對(duì)象的offsetTop+自身的高度+規(guī)定的間隔 offsetTop += item.$el.offsetHeight + offset; }); instance.$el.style.top = offsetTop + 'px'; instances.push(instance); } Message.close = function(instance) { let removeHeight = instance.$el.offsetHeight + instance.offset; let index = instances.findIndex( item => item === instance ); instances = instances.filter( item => item !== instance ); for (let i = index; i<instances.length; i++) { instances[i].$el.style.top = parseFloat(instances[i].$el.style.top) - removeHeight + 'px'; } }; ['info', 'success', 'error', 'warning'].forEach( type => { Message[type] = function(data) { if (typeof data === 'string') { data = { message: data } } data.type = type; //整合data后再次去調(diào)用Message() return Message(data); }; } ); // Message.error=function(data){ // if (typeof data === 'string') { // data = { // message: data // } // } // return Message({ // ...data, // type:'error' // }) // } export default Message
完結(jié)撒花,最后來(lái)看一下效果圖:
總結(jié)
到此這篇關(guān)于通過(guò)vue.extend實(shí)現(xiàn)消息提示彈框的文章就介紹到這了,更多相關(guān)vue.extend實(shí)現(xiàn)消息提示彈框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3實(shí)現(xiàn)canvas畫布組件自定義畫板實(shí)例代碼
Vue?Canvas是一個(gè)基于Vue.js的輕量級(jí)畫板組件,旨在提供一個(gè)簡(jiǎn)易的畫布功能,用戶可以在網(wǎng)頁(yè)上進(jìn)行自由繪圖,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09使用vue插件axios傳數(shù)據(jù)的Content-Type及格式問(wèn)題詳解
這篇文章主要介紹了使用vue插件axios傳數(shù)據(jù)的Content-Type以及格式問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09vue elementui el-form rules動(dòng)態(tài)驗(yàn)證的實(shí)例代碼詳解
在使用elementUI el-form 中,對(duì)于業(yè)務(wù)不同的時(shí)候可能會(huì)產(chǎn)生不同表單結(jié)構(gòu),但是都是存在同一個(gè)表單控件el-form中。這篇文章主要介紹了vue elementui el-form rules動(dòng)態(tài)驗(yàn)證的實(shí)例代碼,需要的朋友可以參考下2019-05-05vue 彈出框 引入另一個(gè)vue頁(yè)面的示例代碼
這篇文章主要介紹了vue 彈出框引入另一個(gè)vue頁(yè)面,這種方式適用于在一個(gè)頁(yè)面邏輯比較多的時(shí)候,可以搞多個(gè)頁(yè)面,防止出錯(cuò),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08vue+element+springboot實(shí)現(xiàn)文件下載進(jìn)度條展現(xiàn)功能示例
本文主要介紹了vue + element-ui + springboot 實(shí)現(xiàn)文件下載進(jìn)度條展現(xiàn)功能,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11vue+mockjs模擬數(shù)據(jù)實(shí)現(xiàn)前后端分離開(kāi)發(fā)的實(shí)例代碼
本篇文章主要介紹了vue+mockjs模擬數(shù)據(jù)實(shí)現(xiàn)前后端分離開(kāi)發(fā)的實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08