<template>
  <view class="s-code-input" :class="c_class" :style="c_style">
    <view
      v-for="(item, index) of list"
      :key="index"
      class="s-code-input__item"
      :style="item_style[index]"
    >
      <view
        v-if="dot && codeValues.length > index"
        class="s-code-input__item__dot"
        :style="dot_style"
      ></view>
      <text v-else class="s-code-input__item__text" :style="text_style">
        {{ codeValues[index] || "" }}
      </text>
      <view
        v-if="mode === 'line'"
        class="s-code-input__item__line"
        :style="line_style"
      ></view>
      <view
        v-if="isFocus && codeValues.length === index"
        :style="cursor_style"
        class="s-code-input__item__cursor"
      ></view>
    </view>
    <input
      :disabled="disabledKeyboard"
      type="number"
      :focus="focus"
      :value="inputValue"
      :maxlength="maxlength"
      class="s-code-input__input"
      :style="input_style"
      @input="handleChange"
      @focus="isFocus = true"
      @blur="isFocus = false"
    />
  </view>
</template>

<script>
import componentMixin from '../../mixins/componentMixin';

/**
 * s-code-input
 * @description 用于验证用户短信验证码的场景
 * @property {Number} maxlength	最大输入长度 （默认 4 ）
 * @property {Boolean} dot 是否用圆点填充 （默认 false ）
 * @property {String} mode 显示模式，box-盒子模式，line-底部横线模式 （默认 'box' ）
 * @property {Boolean} hairline 是否细边框 （默认 false ）
 * @property {String|Number} gutter 字符间的距离 （默认 20 ）
 * @property {String|Number} value 预置值
 * @property {Boolean} focus 是否自动获取焦点 （默认 false ）
 * @property {Boolean} bold 字体和输入横线是否加粗 （默认 false ）
 * @property {String} color 字体颜色
 * @property {String|Number} fontSize 字体大小，单位px （默认 36 ）
 * @property {String|Number} size 输入框的大小，宽等于高 （默认 70 ）
 * @property {Boolean} disabledKeyboard	是否隐藏原生键盘，如果想用自定义键盘的话，需设置此参数为true （默认 false ）
 * @property {String} borderColor 边框和线条颜色
 * @property {String|Number} borderRadius mode等于box时边框圆角 （默认 6 ）
 * @property {Boolean} disabledDot 是否禁止输入"."符号 （默认 true ）
 * @property {String|Object} textStyle 数字样式
 * @property {String|Object} itemStyle 数字块样式
 * @property {String|Object} lineStyle 下划线样式
 * @property {String|Object} dotStyle dot点样式
 * @property {String|Object} cursorStyle 光标样式
 * @event {Function} change(value) 输入内容发生改变时触发，具体见上方说明 value：当前输入的值
 * @event {Function} finish(value) 输入字符个数达maxlength值时触发，见上方说明	value：当前输入的值
 * @example	<s-code-input v-model="value" />
 */
export default {
  name: 'SCodeInput',
  mixins: [componentMixin],
  props: {
    maxlength: {
      type: Number,
      default: 4,
    },
    dot: Boolean,
    mode: {
      type: String,
      default: 'box',
    },
    hairline: Boolean,
    gutter: {
      type: [String, Number],
      default: 20,
    },
    value: {
      type: [String, Number],
      default: '',
    },
    focus: Boolean,
    bold: Boolean,
    color: String,
    fontSize: [String, Number],
    size: [String, Number],
    disabledKeyboard: Boolean,
    borderColor: String,
    borderRadius: {
      type: [String, Number],
      default: 6,
    },
    disabledDot: {
      type: Boolean,
      default: true,
    },
    textStyle: [String, Object],
    itemStyle: [String, Object],
    lineStyle: [String, Object],
    dotStyle: [String, Object],
    cursorStyle: [String, Object],
  },
  data: () => ({
    inputValue: '',
    isFocus: false,
  }),
  computed: {
    c_class() {
      return this.$mergeClass({
        [`s-code-input--${this.mode}`]: this.mode && this.mode !== 'none',
        's-code-input--dot]': this.dot,
      }, this.custom_class);
    },
    c_style() {
      return this.$mergeStyle(this.custom_style);
    },
    input_style() {
      return this.$mergeStyle({
        height: this.$addUnit(this.size),
      });
    },
    list() {
      return new Array(Number(this.maxlength)).fill(1);
    },
    item_style() {
      const { size, mode, hairline, borderColor, gutter, list } = this;
      const borderRadius = this.$addUnit(this.borderRadius);
      return this.list.map((_, index) => {
        const style = {
          width: this.$addUnit(size),
          height: this.$addUnit(size),
        };
        if (index > 0) {
          style.marginLeft = this.$addUnit(gutter);
        }
        if (mode === 'box') {
          style.borderWidth = `${hairline ? 0.5 : 1}px`;
          style.borderColor = borderColor;
          if (this.$toPx(gutter) > 0) {
            style.borderRadius = borderRadius;
          } else {
            if (index === 0) {
              style.borderTopLeftRadius = borderRadius;
              style.borderBottomLeftRadius = borderRadius;
            }
            if (index === list.length - 1) {
              style.borderTopRightRadius = borderRadius;
              style.borderBottomRightRadius = borderRadius;
            }
            if (index !== list.length - 1) {
              style.borderRight = 'none';
            }
          }
        }
        return this.$mergeStyle(style, this.itemStyle);
      });
    },
    text_style() {
      return this.$mergeStyle({
        fontSize: this.$addUnit(this.fontSize),
        fontWeight: this.bold ? 'bold' : '',
        color: this.color,
      }, this.textStyle);
    },
    codeValues() {
      return String(this.inputValue).split('');
    },
    line_style() {
      const style = {};
      style.width = this.$addUnit(this.size);
      style.backgroundColor = this.borderColor;
      return this.$mergeStyle(style, this.lineStyle);
    },
    dot_style() {
      return this.$mergeStyle(this.dotStyle);
    },
    cursor_style() {
      return this.$mergeStyle({
        backgroundColor: this.color,
      }, this.cursorStyle);
    },
  },
  watch: {
    value: {
      immediate: true,
      handler(val) {
        this.inputValue = String(val).substring(0, this.maxlength);
      },
    },
  },
  created() {
    this.isFocus = this.focus;
  },
  methods: {
    handleChange(e) {
      const value = e.detail.value;
      this.inputValue = value;
      // 是否允许输入“.”符号
      if (this.disabledDot) {
        this.$nextTick(() => {
          this.inputValue = value.replace('.', '');
        });
      }
      // 未达到maxlength之前，发送change事件，达到后发送finish事件
      this.$emit('change', value);
      // 修改通过v-model双向绑定的值
      this.$emit('input', value);
      // 达到用户指定输入长度时，发出完成事件
      if (String(value).length >= Number(this.maxlength)) {
        this.$emit('finish', value);
      }
    },
  },
};
</script>

<style lang="scss" src="./index.scss"></style>
