h5实现类似淘宝评价选择标签

<template>
  <div class="comp-box">
    <!-- 标签-标签盒子 -->
    <div class="tag-box">
      <el-tag
        v-for="item in tagOptions"
        size="small"
        :type="item.selected ? '' : 'info'"
        :key="`menu-tag-${item.code}`"
        @click="onClickTag(item)"
        >{{ item.label }}</el-tag
      >
    </div>
    <!-- 标签-评论内容 -->
    <div ref="cmtContBoxRef" class="content">
      <div
        class="tag-item-content"
        v-for="item in contList"
        :key="`cont-item-${item.key}`"
      >
        <div v-if="item.key !== 'txt'" class="label">{{ item.label }}:</div>
        <div
          contenteditable
          class="cont"
          :style="`text-indent: ${
            item.label.length === 0 ? 0 : item.label.length + 1
          }em;`"
          @input="(e) => onChange(e, item)"
        ></div>
      </div>
    </div>
    <div class="tag-item-content-label">{{ describeNum }}/3000</div>
  </div>
</template>
<script>
/**
 * @todo 评论组件
 */
export default {
  name: "Comment",
  props: {
    /**
     * tags.item = { code: "color", label: "标题" },
     * tags.item.code: 标记
     * tags.item.label: 显示的标题
     *
     */
    tags: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      // 评论标签选项
      tagOptions: [],
      // 默认列表文字
      contList: [{ key: "txt", label: "", content: "" }],
      describeNum: 0
    };
  },
  watch: {
    tags: function () {
      // 重载
      this.reloadTagOptions();
    },
    contList: function (nv) {
      // const lastIdx = nv.length - 1;
      console.log("最后一行的内容:", nv);
    },
  },
  mounted() {
    // 重载标签选项
    this.reloadTagOptions();
  },
  methods: {
    // 获取textarea的样式
    textAreaClass(item) {
      return item.key !== "txt" ? "cont tag-input-area" : "cont";
    },
    clean() {
      for (const dom of this.$refs.cmtContBoxRef.children) {
        dom.children[0].innerText = '';
      }
      this.contList = [{ key: "txt", label: "", content: "" }]
    },
    // 重载标签
    reloadTagOptions() {
      this.tagOptions = this.tags.map((e) => {
        return { ...e, selected: false };
      });
    },
    onClickTag(item) {
      const selected = !item.selected;
      if (selected) {
        // 选中
        const newItem = { key: item.code, label: item.label, content: "" };
        const txtItem = this.contList.find((e) => e.key === "txt");
        // 如果只有1行且内容为空
        if (txtItem.content === "") {
          const list = this.contList.filter((e) => {
            return e.key !== "txt";
          });
          list.push(newItem);
          this.contList = [...list, txtItem];
        } else {
          this.contList.push(newItem);
        }
        item.selected = selected;
        let num = 0;
        this.contList.forEach(v => {
          num += v.label.length + v.content.length;
        })
        this.describeNum = num;
      } else {
        // 未选中
        const contItemIndex = this.contList.findIndex(
          (e) => e.key === item.code
        );
        if (this.contList[contItemIndex].content) {
          this.$confirm("已填写的描述将被删除", "确认删除标签?", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(() => {
              this.contList.splice(contItemIndex, 1);
              item.selected = selected;
              let num = 0;
              this.contList.forEach(v => {
                num += v.label.length + v.content.length;
              })
              this.describeNum = num;
            })
            .catch((e) => e);
        } else {
          this.contList.splice(contItemIndex, 1);
          item.selected = selected;
        }
      }
    },
    // 修改
    onChange(e, item) {
      item.content = e.target.innerText;
      let num = 0;
      this.contList.forEach(v => {
        num += v.label.length + v.content.length;
      })
      this.describeNum = num;
      console.log(num);
      
    },
  },
};
</script>
<style lang="scss" scoped>
::v-deep .el-tag {
  margin-right: 10px;
  cursor: pointer;
}
div {
  text-indent: 0em;
}
.comp-box {
  box-sizing: border-box;
  border: 1px solid #dedede;
  background-color: #fafbfc;
  width: 77%;
  // width: 500px;
  padding: 10px;
}
// 标签盒子
.tag-box {
  width: 100%;
}
// 内容
.content {
  width: 100%;
  border: 1px solid #dedede;
  margin-top: 10px;
  background-color: #fefefe;
  min-height: 110px;
  padding: 5px 0px;
  // 标签项
  .tag-item-content {
    font-size: 12px;
    color: #666666;
    position: relative;
    line-height: 22px;
    .label {
      color: #999;
      font-size: inherit;
      position: absolute;
      top: 0px;
      padding-left: 5px;
    }
    .cont {
      outline: none;
      border: none;
      box-sizing: border-box;
      padding: 0px 5px;
      // 只显示文本, 不自动生成标签
      -webkit-user-modify: read-write-plaintext-only;
    }
  }
}
.tag-input-area {
  text-indent: 3em;
}
.btn-box {
  margin-top: 5px;
  text-align: right;
}
.tag-item-content-label {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  color: #999;
}
</style>

效果图
在这里插入图片描述

主要是用到div的contenteditable可编辑属性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值