⑨ 邮件预览效果

1 实现效果

2 组件代码

1. 模板代码 template

<template>
  <template v-if="!noColor">
    <ColorPicker v-model="colorData.color" size="small" :colors="colorData.colors"/>
    <Button size="small" ghost type="primary" @click.native="addColorTag">配色</Button>
  </template>
  <Button v-if="hasHyperLink" class="mr-5" size="small" ghost type="primary" @click.native="addHyperLink">超链接</Button>
  <Button v-if="!noPreview" class="mr-5" size="small" ghost type="primary" @click.native="previewClick">预览</Button>
  <slot></slot>
  <Input v-if="!inputSelector" ref="editorRef" type="textarea" :value="content" placeholder="请输入内容" :autosize="{ minRows:3, maxRows: 8 }" @input="inputChange"></Input>
</template>

2. 处理应用程序逻辑 ColorDataCls类

2.1 邮件预设颜色常量 MAIL

const MAIL = {
  defaultColor: '#9d1802',
  createPresetColors: function(type) {
    switch (type) {
      case 'notice':
        return ['#9d1802', '#00800f', '#964129'];
      default:
        return ['#9d1802', '#00800f', '#e57c00', '#3ef672', '#964129'];
    }
  }
}

2.2 构造者函数+基本功能

class ColorDataCls {
  constructor(props) {
    this.color = MAIL.defaultColor; // 目前颜色
    this.colors = MAIL.createPresetColors(); // 颜色列表
    props && Object.assign(this, props);
  }
  // 静态方法 为选中文字添加颜色标签
  static addColorTag(inputEle, inputContent, color) {}
  // 静态方法 为选中文字添加超链接
  static addHyperLink(inputEle, inputContent) {}
  // 静态方法 标签转换
  static previewContentTransform(inputEle) {}
}

3. 父组件可传递属性 props

export default {
  let idNum = 0;
  createId() {
    return `CWID${idNum++}`;
  },
  props: {
    content: String,
    // 去掉配色
    noColor: Boolean,
    // +超链接
    hasHyperLink: Boolean,
    // 去掉预览按钮
    noPreview: Boolean,
    // css选择器,存在:不用组件的文本框
    // 注意:谨防选择器重复,比如 Modal 会提升到 body,跳转标签时会继续存在
    inputSelector: String,
    // 颜色数据,默认用邮件色值
    colorData: {
      type: Object,
      default() {
        return new ColorDataCls();
      }
    }
  }
}

4. 事件处理程序

4.1 配色

addColorTag() {
  let element = 
    this.inputSelector ?
      document.querySelector(this.inputSelector) : this.$refs.editorRef.$refs.textarea;
  this.$emit(
    'update:content',
    ColorDataCls.addColorTag(element, this.content, this.colorData.color)
  );
  this.$emit('addColor', this.colorData.color);
}

4.2 预览

previewClick() {
  this.$emit(
    'preview',
    ColorDataCls.previewContentTransform(this.content)
  );
}

4.3 监听输入框事件

inputChange(value) {
  this.$emit('update:content', value);
}

5. 处理应用程序逻辑具体实现

5.1 为选中文字添加颜色标签

static addColorTag(inputEle, inputContent, color) {
  let rangeData = {
    text: '',
    start: 0,
    end: 0
  };
  if(inputEle.setSelectionRange) {
    rangeData.start = inputEle.selectionStart;
    rangeData.end = inputEle.selectionEnd;
    rangeData.text =
      rangeData.start != rangeData.end ?
        inputContent.slice(rangeData.start, rangeData.end) : '';

    return `${inputContent.slice(0, rangeData.start)}<color=${color}>${rangeData.text}</color>${inputContent.slice(rangeData.end)}`;
  }
}

5.2 标签转换

static previewContentTransform(inputEle) {
  return inputContent
          .replace(/\n/g, '<br/>')
          .replace(/\s/g, '&nbsp')
          .replace(/(size=|color=)/g, 'font $1')
          .replace(/(size>|color>)/g, 'font>')
          .replace(/<a\&nbsp/g, "<a style='font-size:22px; color:#379a61; text-decoration:underline' target='_blank' ")
}

5.3 有限层标签嵌套

static changeColorRegs(content) {
  const reg = /\[color=(.*?)\]((\[color=(.*?)\](.*?)\[\/color\]|.)*?)\[\/color\]/g
  return content.replace(reg, (match, p1, p2) => {
    let str = `<span style="color: ${p1}">`
    if(reg.test(p2)) {
      return str + this.changeColorRegs(p2) + '</span>'
    } else {
      return str + p2 + '</span>'
    }
  })
}

5.4 找到闭合标签的前一个同类型起始标签实现配对

static changeColorRegs(content, contentFlage) {
  const regBegin = /\[color=(.*?)\]/ // 起始标签
  const regFindLast = /(.*)\[color=(.*?)\](.*)/g // 最后一个匹配的起始标签
  const regContent = /(\[color=.*?\][\s\S]*?)(?=\[\/color\])\[\/color\]/g // 找到闭合标签的前一个起始标签
  return content.replace(regContent, (match, p1) => {
    if(regBegin.test(p1)) {
      return p1.replace(regFindLast, (inner_match, inner_p1, inner_p2, inner_p3) => {
        if(regBegin.test(inner_p1)) {
          contentFlage.colorFlage = true
        }
        return `${inner_p1}<span style="color: ${inner_p2}">${inner_p3}</span>`
      })
    }
    return match
  })
}
static previewContentTransform(inputContent) {
  let content = inputContent
      .replace(/</g, '&lt')
      .replace(/>/g, '&gt')
      .replace(/\n/g, '<br/>')
      .replace(/\s/g, '&nbsp')

  let contentFlage = {
    colorFlage: false,
    sizeFlage: false,
    bFlage: false,
  }
  do {
    contentFlage.colorFlage = false
    content = this.changeColorRegs(content, contentFlage)
  } while(contentFlage.colorFlage)
  return content
}

3 应用

3.1 配色+预览

<color-wrapper :content.sync="pepper.data.content" @preview="mailPreviewOpen">
  <span class="text-danger">{money}替换档位金额数</span>
</color-wrapper>
<!-- v-html -->
<mail-preview :data="mailPreviewData"></mail-preview>
mailPreviewOpen(content) {
  let molData = this.pepper.data;
  this.mailPreviewData.title = molData.title;
  // 内容
  this.mailPreviewData.content = content;
  this.mailPreviewData.isDisplay = true;
}
posted on 2023-02-09 11:58  pleaseAnswer  阅读(60)  评论(0编辑  收藏  举报