[vue]自行實做一個彈跳小視窗的元件,並關閉其他同樣的元件
這次想要來寫下我如何自行製作一個類似tooltip,但是裡面可以自行決定放任何內容的元件,有興趣的人可以看看我的做法,或者你也可以提供更好的作法給筆者。
做完的效果會類似如下。
而component會使用slot來放兩塊可取代的,一個是中間筆者想自行實做的,而另一個則是footer固定的button按鈕,此元件的原始碼大約如下
<template>
<div ref="editable">
<a style="display:block;color:blue" @click="click">{{value}}</a>
<div v-if="isPopup" class="vue-popUpSmall" :style="popPosition">
<slot/>
<slot name="footer">
<div class="text-center">
<div class="button">
<input type="button" value="submit" class="btn_refresh refresh_roll tool_goal_submit" @click="$emit('submit')"
/>
</div>
<div class="button">
<input type="button" value="Cancel" class="btn_refresh refresh_roll" @click="cancel" />
</div>
</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'editable',
props: {
value: {
type: [Number, String]
},
position: {
type: String,
default: '0'
}
},
data() {
return {
isPopup: false
}
},
computed: {
popPosition() {
return `margin-left:${this.position}`
}
},
methods: {
close() {
this.isPopup = false
},
click() {
this.isPopup = !this.isPopup
},
cancel() {
this.isPopup = false
}
}
}
</script>
<style lang="scss" scoped>
.vue-popUpSmall {
position: absolute;
background-color: #e6e6e6;
border: 4px solid #b9b9b9;
color: #000000;
padding: 5px;
max-height: 300px;
z-index: 1;
}
td {
border: 0;
padding: 2px;
}
.button {
display: inline;
margin: 2px;
}
</style>
而這元件的使用方式,大約會如下程式碼
<ul>
<li v-for="item in viewModel.events" :key="item.eventId">
<editable v-model="item.eventId">
<table>
<tr>
<td class="text-right">
<span>Test 1 :</span>
</td>
<td>
<input type="text">
</td>
</tr>
<tr>
<td class="text-right">
<span>Test 2 :</span>
</td>
<td>
<input type="text">
</td>
</tr>
</table>
</editable>
</li>
</ul>
但事情還沒完,因為此元件當點了的時候,其實要關閉畫面上所有其他的元件,但目前卻可以一直點出不同位置的元件
接著再來把此元件修改一下,說明直接註解寫在元件裡面。
<template>
<div ref="editable">
<a style="display:block;color:blue" @click="click">{{value}}</a>
<div v-if="isPopup" class="vue-popUpSmall" :style="popPosition">
<slot/>
<slot name="footer">
<div class="text-center">
<div class="button">
<input type="button" value="submit" class="btn_refresh refresh_roll tool_goal_submit" @click="$emit('submit')"
/>
</div>
<div class="button">
<input type="button" value="Cancel" class="btn_refresh refresh_roll" @click="cancel" />
</div>
</div>
</slot>
</div>
</div>
</template>
<script>
export default {
name: 'editable',
props: {
value: {
type: [Number, String]
},
position: {
type: String,
default: '0'
}
},
data() {
return {
isPopup: false
}
},
computed: {
popPosition() {
return `margin-left:${this.position}`
}
},
methods: {
close() {
this.isPopup = false
},
click() {
this.$emit('click')
this.isPopup = !this.isPopup
},
cancel() {
this.isPopup = false
},
documentClick(e) {
let el = this.$refs.editable
// 下面最主要目的是為了比對如果el和e.target取得的dom有不相同,或不包含的話,就把視窗關閉起來
if (el !== e.target && !el.contains(e.target)) {
this.isPopup = false
}
}
},
mounted() {
//監聽dom的click事件
document.addEventListener('click', this.documentClick)
},
destroyed() {
//銷毀元件的時候,記得要remove以防memory leak
document.removeEventListener('click', this.documentClick)
}
}
</script>
<style lang="scss" scoped>
.vue-popUpSmall {
position: absolute;
background-color: #e6e6e6;
border: 4px solid #b9b9b9;
color: #000000;
padding: 5px;
max-height: 300px;
z-index: 1;
}
td {
border: 0;
padding: 2px;
}
.button {
display: inline;
margin: 2px;
}
</style>
最後完成的簡單範例就會如下圖示例
如果有更好的做法,再請告知筆者哦。