Vue.jsでTeamsみたいなメンションをテキストエリアに実装する「vue-mention」
by kabanoki
HTML
<div id="app">
<mentionable
:keys="['@', '#']"
:items="items"
offset="6"
@open="onOpen"
>
<textarea v-model="text" class="form-control" rows="8"></textarea>
<template #no-result>
<div class="dim">
No result
</div>
</template>
<template #item-@="{ item }">
<div class="user">
{{ item.value }}
<span class="dim">
({{ item.firstName }})
</span>
</div>
</template>
<template #item-#="{ item }">
<div class="issue">
<span class="number">
#{{ item.value }}
</span>
<span class="dim">
{{ item.label }}
</span>
</div>
</template>
</mentionable>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://unpkg.com/[email protected]/dist/v-tooltip.min.js"></script>
<script>
const vTooltip = VTooltip;
Vue.use(VTooltip);
</script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-mention.min.js"></script>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.tooltip {
display: block!important;
z-index: 10000
}
.tooltip .tooltip-inner {
background: #000;
color: #fff;
border-radius: 16px;
padding: 5px 10px 4px
}
.tooltip .tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
border-color: #000;
z-index: 1
}
.tooltip[x-placement^=top] {
margin-bottom: 5px
}
.tooltip[x-placement^=top] .tooltip-arrow {
border-width: 5px 5px 0;
border-left-color: transparent!important;
border-right-color: transparent!important;
border-bottom-color: transparent!important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0
}
.tooltip[x-placement^=bottom] {
margin-top: 5px
}
.tooltip[x-placement^=bottom] .tooltip-arrow {
border-width: 0 5px 5px;
border-left-color: transparent!important;
border-right-color: transparent!important;
border-top-color: transparent!important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0
}
.tooltip[x-placement^=right] {
margin-left: 5px
}
.tooltip[x-placement^=right] .tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent!important;
border-top-color: transparent!important;
border-bottom-color: transparent!important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0
}
.tooltip[x-placement^=left] {
margin-right: 5px
}
.tooltip[x-placement^=left] .tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent!important;
border-right-color: transparent!important;
border-bottom-color: transparent!important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0
}
.tooltip.popover .popover-inner {
background: #f9f9f9;
...
Vue
const Mentionable = window['VueMention'].Mentionable;
new Vue({
el: '#app',
components: {
'mentionable': Mentionable,
},
data: {
text: '',
items: [],
users: [
{
value: 'akryum',
firstName: 'Guillaume',
},
{
value: 'posva',
firstName: 'Eduardo',
},
{
value: 'atinux',
firstName: 'Sébastien',
},
],
issues: [
{
value: 123,
label: 'Error with foo bar',
searchText: 'foo bar'
},
{
value: 42,
label: 'Cannot read line',
searchText: 'foo bar line'
},
{
value: 77,
label: 'I have a feature suggestion',
searchText: 'feature'
}
]
},
methods: {
onOpen:function (key) {
this.items = key === '@' ? this.users : this.issues
},
},
});