Skip to content

fritx/vue-at

Repository files navigation

vue-at

        Join the chat at https://gitter.im/fritx/vue-at

  

  • Chrome / Firefox / Edge / IE9~IE11
  • Plain-text based, no jQuery, no extra nodes
  • Content-Editable / Textarea
  • Avatars, custom templates
  • Vue3 / Vue2 / Vue1
  • Vuetify / Element UI / Element Plus
  • Vue-CLI migration
  • Vite migration

Playground: https://we-demo.github.io/vue-at-vite-app/
Vue3 Docs: https://github.com/fritx/vue-at/tree/vue3#readme
Vue2 Docs: https://fritx.github.io/vue-at/ or see below
See also: react-at

Motivation

At.js is awesome, but:

  • It is based on jQuery and jQuery-Caret.
  • It introduces extra node wrappers.
  • It could be unstable on content edit/copy/paste.

Finally I ended up creating this.

If you're using Vue3, read branch vue3 instead.

npm i vue-at@next  # for Vue3 (branch vue3)
npm i vue-at@2.x  # for Vue2 (branch vue2)
npm i vue-at@1.x  # for Vue1 (branch vue1-legacy)
npm i vue1-at  # for Vue1 (branch vue1-new)
<template>
  <at :members="members">
    <div contenteditable></div>
  </at>
</template>

<script>
import At from 'vue-at'

export default {
  components: { At },
  data () {
    return {
      members: ['Roxie Miles', 'grace.carroll', '小浩']
    }
  }
}
</script>

<style>
#app .atwho-view { /* more */ }
#app .atwho-ul { /* more */ }
</style>

Using V-Model (Recommended)

With Content-Editable, v-model should be bound in <at> container.
With Textarea, v-model should be bound in <textarea> itself.

<at v-model="html">
  <div contenteditable></div>
</at>

<at-ta>
  <textarea v-model="text"></textarea>
</at-ta>

Textarea

<template>
  <at-ta>
    <textarea></textarea>
  </at-ta>
</template>

<script>
// import At from 'vue-at' // for content-editable
import AtTa from 'vue-at/dist/vue-at-textarea' // for textarea

export default {
  components: { AtTa }
}
</script>
npm i -S textarea-caret  # also, for textarea

Custom Templates

Custom List

<template>
  <at :members="members" name-key="name">
    <template slot="item" slot-scope="s">
      <img :src="s.item.avatar">
      <span v-text="s.item.name"></span>
    </template>
    <div contenteditable></div>
  </at>
</template>

<script>
// ...
members: [{
  avatar: 'https://randomuser.me/api/portraits/men/2.jpg',
  name: 'myrtie.green'
}, {
  avatar: 'https://randomuser.me/api/portraits/men/8.jpg',
  name: '椿木'
}]
</script>

<style>
#app .atwho-li { /* more */ }
#app .atwho-li img { /* more */ }
#app .atwho-li span { /* more */ }
</style>

Custom List with Vue 1.x

There is no "scoped slot" feature in Vue 1.
Use a "normal slot" with data- attribute instead.

<!-- vue1-at for vue@1.x -->
<template slot="item">
  <img data-src="item.avatar">
  <span data-text="item.name"></span>
</template>

Custom Tags

This gives you the option of changing the style of inserted tagged items. It is only supported for ContentEditable version, not Textarea.

<span slot="embeddedItem" slot-scope="s">
  <span class="tag"><img :src="s.current.avatar">{{ s.current.name }}</span>
</span>

<!-- with Vue 2.6+ 'v-slot' directive -->
<!-- note at least two '<span>' wrapper are required to work -->
<template v-slot:embeddedItem="s">
  <span><span class="tag"><img class="avatar" :src="s.current.avatar">{{ s.current.name }}</span></span>
</template>

Used with 3rd-party libraries

Vuetify v-textarea

<at-ta :members="members">
  <!-- slots -->
  <v-textarea v-model="text"></v-textarea>
</at-ta>

Element-UI el-input

<at-ta :members="members">
  <!-- slots -->
  <el-input v-model="text" type="textarea"></el-input>
</at-ta>