当前位置: 移动技术网 > IT编程>开发语言>JavaScript > element-ui Rate组件源码分析整理笔记(十三)

element-ui Rate组件源码分析整理笔记(十三)

2019年08月29日  | 移动技术网IT编程  | 我要评论

rate组件源码比较简单,有添加部分注释

main.vue

<template>
    <!--valuenow当前的评分 valuetext当前显示的文本-->
  <div
    class="el-rate"
    @keydown="handlekey"
    role="slider"
    :aria-valuenow="currentvalue"
    :aria-valuetext="text"
    aria-valuemin="0"
    :aria-valuemax="max"
    tabindex="0">
      <!--包裹每个星的标签-->
    <span
      v-for="(item, key) in max"
      class="el-rate__item"
      @mousemove="setcurrentvalue(item, $event)"
      @mouseleave="resetcurrentvalue"
      @click="selectvalue(item)"
      :style="{ cursor: ratedisabled ? 'auto' : 'pointer' }"
      :key="key">
        <!--显示评星的标签-->
      <i :class="[classes[item - 1], { 'hover': hoverindex === item }]"
        class="el-rate__icon"
        :style="geticonstyle(item)">
          <!--这里主要是当评分出现小数,显示左边高亮的半星-->
        <i v-if="showdecimalicon(item)"
          :class="decimaliconclass"
          :style="decimalstyle"
          class="el-rate__decimal">
        </i>
      </i>
    </span>
      <!--showtext是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容;showscore是否显示当前分数,show-score 和 show-text 不能同时为真-->
    <span v-if="showtext || showscore" class="el-rate__text" :style="{ color: textcolor }">{{ text }}</span>
  </div>
</template>

<script>
  import { hasclass } from 'element-ui/src/utils/dom';
  import migrating from 'element-ui/src/mixins/migrating';

  export default {
    name: 'elrate',

    mixins: [migrating],
    //provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。
    inject: {
      elform: {
        default: ''
      }
    },

    data() {
      return {
        pointeratlefthalf: true,
        currentvalue: this.value,
        hoverindex: -1
      };
    },

    props: {
      value: {
        type: number,
        default: 0
      },
      lowthreshold: { //低分和中等分数的界限值,值本身被划分在低分中
        type: number,
        default: 2
      },
      highthreshold: { //高分和中等分数的界限值,值本身被划分在高分中
        type: number,
        default: 4
      },
      max: { //最大分值
        type: number,
        default: 5
      },
      colors: { //icon 的颜色数组,共有 3 个元素,为 3 个分段所对应的颜色
        type: array,
        default() {
          return ['#f7ba2a', '#f7ba2a', '#f7ba2a'];
        }
      },
      voidcolor: { //未选中 icon 的颜色
        type: string,
        default: '#c6d1de'
      },
      disabledvoidcolor: { //只读时未选中 icon 的颜色
        type: string,
        default: '#eff2f7'
      },
      iconclasses: { //icon 的类名数组,共有 3 个元素,为 3 个分段所对应的类名
        type: array,
        default() {
          return ['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on'];
        }
      },
      voidiconclass: { //未选中 icon 的类名
        type: string,
        default: 'el-icon-star-off'
      },
      disabledvoidiconclass: { //只读时未选中 icon 的类名
        type: string,
        default: 'el-icon-star-on'
      },
      disabled: { //是否为只读
        type: boolean,
        default: false
      },
      allowhalf: { //是否允许半选
        type: boolean,
        default: false
      },
      showtext: { //是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容
        type: boolean,
        default: false
      },
      showscore: { //是否显示当前分数,show-score 和 show-text 不能同时为真
        type: boolean,
        default: false
      },
      textcolor: { //辅助文字的颜色
        type: string,
        default: '#1f2d3d'
      },
      texts: {  //辅助文字数组
        type: array,
        default() {
          return ['极差', '失望', '一般', '满意', '惊喜'];
        }
      },
      scoretemplate: {  //分数显示模板
        type: string,
        default: '{value}'
      }
    },

    computed: {
      text() {
        let result = '';
        //如果显示当前分数
        if (this.showscore) {
          //如果当前是只读状态,就显示v-model绑定的值,否则根据用户的评分显示值
          result = this.scoretemplate.replace(/\{\s*value\s*\}/, this.ratedisabled
            ? this.value
            : this.currentvalue);
        } else if (this.showtext) { //如果显示辅助文字,则根据用户设置评分currentvalue来显示texts数组中的文字
          result = this.texts[math.ceil(this.currentvalue) - 1];
        }
        return result;
      },
      //高亮半星时添加的样式,颜色以及宽度
      decimalstyle() {
        let width = '';
        if (this.ratedisabled) {
          //这里判断value的值是否含有小数,有小数的则这里宽度为50%,为整数的话为0%
          width = `${ this.valuedecimal < 50 ? 0 : 50 }%`;
        }
        if (this.allowhalf) {
          width = '50%';
        }
        return {
          color: this.activecolor,
          width
        };
      },

      valuedecimal() {
        return this.value * 100 - math.floor(this.value) * 100;
      },

      decimaliconclass() {
        return this.getvaluefrommap(this.value, this.classmap);
      },

      voidclass() {
        return this.ratedisabled ? this.classmap.disabledvoidclass : this.classmap.voidclass;
      },
      //根据currentvalue的分所在的等级,返回对应的类名
      activeclass() {
        return this.getvaluefrommap(this.currentvalue, this.classmap);
      },

      colormap() {
        return {
          lowcolor: this.colors[0],
          mediumcolor: this.colors[1],
          highcolor: this.colors[2],
          voidcolor: this.voidcolor,
          disabledvoidcolor: this.disabledvoidcolor
        };
      },
      //根据currentvalue的分所在的等级,返回对应的颜色
      activecolor() {
        return this.getvaluefrommap(this.currentvalue, this.colormap);
      },
      //这里主要是判断该星是选中还是未选中,分别加入选中和未选中icon类名
      classes() {
        let result = [];
        let i = 0;
        let threshold = this.currentvalue;
        if (this.allowhalf && this.currentvalue !== math.floor(this.currentvalue)) {
          threshold--;
        }
        for (; i < threshold; i++) {
          result.push(this.activeclass);
        }
        for (; i < this.max; i++) {
          result.push(this.voidclass);
        }
        return result;
      },

      classmap() {
        return {
          lowclass: this.iconclasses[0],
          mediumclass: this.iconclasses[1],
          highclass: this.iconclasses[2],
          voidclass: this.voidiconclass,
          disabledvoidclass: this.disabledvoidiconclass
        };
      },

      ratedisabled() {
        //是否为只读,或者父组件el-form中disabled的属性值,disabled是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效
        return this.disabled || (this.elform || {}).disabled;
      }
    },

    watch: {
      value(val) {
        this.currentvalue = val;
        this.pointeratlefthalf = this.value !== math.floor(this.value);
      }
    },

    methods: {
      getmigratingconfig() {
        return {
          props: {
            'text-template': 'text-template is renamed to score-template.'
          }
        };
      },
      //判断当前value在属于低分、中等分、高分中的哪个,根据不同等级返回不同的类名或者颜色
      getvaluefrommap(value, map) {
        let result = '';
        if (value <= this.lowthreshold) {
          result = map.lowcolor || map.lowclass;
        } else if (value >= this.highthreshold) {
          result = map.highcolor || map.highclass;
        } else {
          result = map.mediumcolor || map.mediumclass;
        }
        return result;
      },

      showdecimalicon(item) {
        //如果当前value包含小数,并且item - 1 < this.value <item, showwhendisabled为true
        let showwhendisabled = this.ratedisabled && this.valuedecimal > 0 && item - 1 < this.value && item > this.value;
        //这里主要也是判断是否当前星是否应显示半星
        let showwhenallowhalf = this.allowhalf &&
          this.pointeratlefthalf &&
          item - 0.5 <= this.currentvalue &&
          item > this.currentvalue;
        return showwhendisabled || showwhenallowhalf;
      },
      //返回当前星图标的颜色
      geticonstyle(item) {
        //voidcolor的值是根据是否只读来判断返回disabled-void-color或者void-color
        const voidcolor = this.ratedisabled ? this.colormap.disabledvoidcolor : this.colormap.voidcolor;
        return {
          //判断当前星是显示高亮的颜色还是未选中时的颜色
          color: item <= this.currentvalue ? this.activecolor : voidcolor
        };
      },
       //点击时设置值
      selectvalue(value) {
        if (this.ratedisabled) {
          return;
        }
        //当可以显示半星时,这块传递的值为currentvalue(鼠标移上去时会计算是否超过一半)
        if (this.allowhalf && this.pointeratlefthalf) {
          this.$emit('input', this.currentvalue);
          this.$emit('change', this.currentvalue);
        } else { //当不显示半星直接返回value
          this.$emit('input', value);
          this.$emit('change', value);
        }
      },
      //当按键按下时所调用的方法
      handlekey(e) {
        //如果组件被禁用则按键事件无效
        if (this.ratedisabled) {
          return;
        }
        let currentvalue = this.currentvalue;
        const keycode = e.keycode;
        //当按上下左右键的时候,允许半选则在currentvalue加或减0.5,不允许则加或减1
        if (keycode === 38 || keycode === 39) { // up / right
          if (this.allowhalf) {
            currentvalue += 0.5;
          } else {
            currentvalue += 1;
          }
          e.stoppropagation();
          e.preventdefault();
        } else if (keycode === 37 || keycode === 40) { // left /down
          if (this.allowhalf) {
            currentvalue -= 0.5;
          } else {
            currentvalue -= 1;
          }
          e.stoppropagation();
          e.preventdefault();
        }
        currentvalue = currentvalue < 0 ? 0 : currentvalue;
        currentvalue = currentvalue > this.max ? this.max : currentvalue;
        //将currentvalue通过input传递给子组件绑定的v-model值,触发change事件,子组件可以change在获取改变后的值
        this.$emit('input', currentvalue);
        this.$emit('change', currentvalue);
      },
      //鼠标移动时改变评星的值
      setcurrentvalue(value, event) {
        if (this.ratedisabled) {
          return;
        }
        /* istanbul ignore if */
        if (this.allowhalf) {
          let target = event.target;
          //鼠标移动到包裹星星图标的span标签时,获取到显示星的icon标签
          if (hasclass(target, 'el-rate__item')) {
            target = target.queryselector('.el-rate__icon');
          }
          if (hasclass(target, 'el-rate__decimal')) {
            target = target.parentnode;
          }
          //根据鼠标移到一颗星的左边一半以内的位置,则减去当前值的0.5,否则就是等于当前值
          this.pointeratlefthalf = event.offsetx * 2 <= target.clientwidth;
          this.currentvalue = this.pointeratlefthalf ? value - 0.5 : value;
        } else {
          //不允许半选时,鼠标移到那颗星就等于当前的值
          this.currentvalue = value;
        }
        //记录鼠标移动的位置
        this.hoverindex = value;
      },
      //鼠标移出时设置当前的值
      resetcurrentvalue() {
        if (this.ratedisabled) {
          return;
        }
        if (this.allowhalf) {
          //如果当前的value是小数,pointeratlefthalf为true,如果是整数则为false,这里主要是为了点击时用来判断传哪个值
          this.pointeratlefthalf = this.value !== math.floor(this.value);
        }
        //鼠标移上去时currentvalue会改变,移走时currentvalue等于之前的value
        this.currentvalue = this.value;
        this.hoverindex = -1;
      }
    },

    created() {
      if (!this.value) {
        this.$emit('input', 0);
      }
    }
  };
</script>

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网