# 评论页

# 技术点

自定义输入框 contenteditable 操作光标位置 resize事件监听

# 目录结构

└─ src
   └─ views
      └─ comment                        # 评论页
         ├─ components                  # 评论组件
         │  ├─ CommentBar.vue           # 评论底部 bar
         │  ├─ CommentEditor.vue        # 评论输入框
         │  ├─ CommentItem.vue          # 评论内容
         │  ├─ CommentSkeleton.vue      # 评论加载骨架
         │  └─ CommentTool.vue          # 评论举报等操作 action-sheet
         └─ index.vue                   # 评论入口页

# 功能介绍

因为多种资源存在评论功能,如文章、影评、视频等,所以将该页面单独抽离出来作为一个公共页面。 注意,该评论页面为弹窗的子页面,以实现用户返回操作时,只关闭评论的弹窗。
comment-bar 组件中,输入框为 div 元素,不是真实输入框。用户点击后,路由插入 hash#edit,以使用户点击返回按钮时只关闭评论框。
comment-editor 组件中,使用 divcontenteditable 属性模拟输入框,为何未使用 input 或者 textarea 呢? input 只能一行,textarea 编辑时光标位置无法移动到最后,不支持表情等。

# 主要代码

CommentEditor 组件

<!-- 评论输入框 -->
<div
  @input="inputChange"
  contenteditable
  ref="input"
  class="comment-edit"
  :style="style"
  autosize
  placeholder="爱笑的人运气不会太差~"
></div>
mounted() {
  // 注册页面 `resize` 事件,当软键盘收起时,则关闭输入框页面
  const _this = this;

  let originalHeight = document.documentElement.clientHeight || document.body.clientHeight;

  window.onresize = function () {
    //键盘弹起与隐藏都会引起窗口的高度发生变化
    let resizeHeight =
      document.documentElement.clientHeight || document.body.clientHeight;

    if (resizeHeight - 0 < originalHeight - 0) {
      //软键盘弹起
    } else {
      //软键盘收起
      _this.$router.back();
    }
  };

  // 如果输入框有内容时关闭输入框,再次打开时,还原之前输入内容
  // 还原后光标会在最前方,需要移动至最后
  this.$nextTick(() => {
    this.$refs.input.focus();

    let range = window.getSelection();
    range.selectAllChildren(this.$refs.input);
    range.collapseToEnd(); //光标移至最后

    setTimeout(() => {
      this.inputFocus();
    }, 300);
  });
},

methods: {
  // 该方法是为了计算去掉软键盘与边距等高度后,可输入内容区域剩余高度
  inputFocus() {
    const height = window.innerHeight - 112;
    this.style = `max-height: ${height}px`;
  }
}
上次更新: 6/27/2022, 5:48:02 PM
示例展示,因PC端无touch事件,请在手机上进行浏览