git clone从https://github.com/chentianwei411/at-mentions-with-action-text
先fork下来,然后拷贝https连接,最后在terminal上:
git clone https://github.com/chenwei/at-mentions-with-action-text.git
然后因为ruby 和 rails版本。使用命令:
rvm 2.6.1@railsXXX版本 #简单的集合命令,详细看之前的相关博客。
根据提示安装bundler和yarn更新。
10821 gem install bundler:2.0.1
10822 bundle update
10828 yarn install --check-files
最后rails db:migrate并rails s启动服务器localhost:3000
rails6.1后: Module#parent_name帮助方法被替换:
# config.application_name = Rails.application.class.parent_name config.application_name = Rails.application.class.module_parent_name
实做@mention功能
使用tribute库来实现@mention功能,支持Vue。
参考https://zurb.github.io/tribute/example/案例,在输入框输入@可以显示人名的下拉列表。
trix文本编辑器已经被集成到新版本。
使用stimulus.js增加JavaScript脚本。
rails webpacker:install:stimulus
然后下载ZURB tribute javascript library。这里使用yarn,也可以用gem 'tribute'
https://github.com/zurb/tribute
这是用ES6写的@mention引擎。无需依赖dependencies。跨浏览器。
yarn add tributejs
按照路径->controller->view思路:
routes.rb内添加:
resources :mentions, only: [:index]
目的是点击这个url来自动获取users。然后就可以动态地load. json格式的user数据。?
创建 controllers mentions controller
class MentionsController < ApplicationController def index @users = User.all respond_to do |format| format.json end end end
⚠️,演示是取全部的user,实际上线版本只取一般前10个用户名字。
创建views/mentions/index.json.jbuilder
json.array! @users, partial: "users/users", as: :user
得到一个array of users, 然后返回partial, 数据名字是user。
创建app/views/users/_user.json.jbuilder
#从user提取它们的id , name json.extract! user, :id, :name
json.sgid user.attachable_sgid
json.content render(partial: "users/user", locals: {user: user}, format: [:html])
解释:
1. json.sgid user.attachable_sgid
需要在modles/User.rb内include一个模块,以便使用方便的方法, ?的user.attachable_sgid。
include ActionText::Attachable
2. json.conent。 渲染views/users/_user.html.erb,传入数据user,格式是html。
创建views/users/_user.html.erb
class="mention"> <%= image_tag gravatar_image_url(user.email, size: 40), height: 20, width: 20, class: "rounded" %> <%= user.name %>
- 启动服务器
- localhost:3000/mentions.json可以看到从数据库取得的用户数据和渲染的视图代码。
下一步:修改post表格,在rich text area增加一个controller和target。
即使用Stimulus的data-target来取这个元素。
class="form-group"> <%= form.label :body %> <%= form.rich_text_area :body, class: 'form-control', data: { controller: "mentions", target: "mentions.field" } %>
创建app/javascript/controllers/mentions_controller.js
import { Controller } from 'stimulus' export default class extends Controller { static targets = ["field"] #定位到post视图的元素上。 contect() {
this.editor = this.fieldTarget.editor
this.initializeTribute() #初始化tribute
}
initializeTribute() {
...
} }
为了使用Tribute需要import
...
import Tribute from 'tributejs' import Trix from 'trix'
...
initializeTribute() { this.tribute = new Tribute({ allowSpaces: true, #集合中的方法,可以在mentions中有空格 lookup: 'name', #集合中的方法,在对象中搜索对应的column(函数或字符串) values: this.fetchUsers, #必须的(required)通过异步函数获得一个数组对象,用于匹配。 })
this.tribute.attach(this.fieldTarget) #把tribute实例连接到元素上。
... }
异步函数:fetchUsers
fetchUsers(text, callback) { fetch(`/mentions.json?query=${text}`) .then(response => response.json()) .then(users => callback(users)) .catch(error => callback([])) }
当不需要监听事件了用disconnect来从元素上移除Tribute实例:
disconnect() {
this.tribute.detach(this.fieldTarget)
}
此时如果在http://localhost:3000/posts/1/edit上尝试,会出现@undefined, 这是因为没有实际 插入value。改用使用事件tribute-replaced。
在initializeTribute()函数内添加
// 点击后回退一个字符,即去掉@: this.tribute.range.pasteHtml = this._pasteHtml.bind(this) // 给目标元素添加事件,当完成 this.fieldTarget.addEventListener("tribute-replaced", this.replaced)
添加函数replaced:
这里要参考Trix api文档:https://github.com/basecamp/trix
replaced(e) { console.log(e) // 得到事件中的数据 let mention = e.detail.item.original // 创建Trix.Attachment,然后调用insertAttachment方法来插入HTML let attachment = new Trix.Attachment({ sgid: mention.sgid, content: mention.content }) this.editor.insertAttachment(attachment) // 再插入一个空格,具体见Trix Api. this.editor.insertString(" ") }
添加_pasteHtml函数:
_pasteHtml(html, startPos, endPos) { let position = this.editor.getPosition() //2个Trix方法 this.editor.setSelectedRange([position - endPos, position]) this.editor.deleteInDirection("backward") }
一个bug: post更新后,再次编辑,@mention内容不可见。当前解决方法是在user.rb添加:
def to_trix_content_attachment_partial_path
to_partial_path
end
如何使用Tributejs库(见git)
- 初始化new Tribute({ ... })
- 把Tribute附加到元素。如input, textarea。 例如:tribute.attach(元素的位置)
- lookup column。必填项,可以是一个函数。
- 函数selectTemplate和menuItemTemplate用于存取item object,即当点击选中的项目后,的显示。
- 事件tribute-replaced。 可以给目标元素绑定这个事件,用于知道何时完成更新目标tribute元素
- 最后,不需要了,就detach Tribute实例,从元素上分开移除Tribute。使用tribute.detach(元素位置)。这会移除所有的实际监听