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


    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*values*}/, 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>
    
    
  • 相关阅读:
    SQL Server常用到的几个设置选项
    动态加载母版页
    Sql查询技巧
    【WP7】关于磁贴的使用
    ashx,页面一般情况下不能方法session,必须添加两个接口。才能访问session。 狼
    悟头javascript学习笔记 狼
    IIS处理简介, IHttpHandler ,IHttpModel 狼
    在IIS下,不能执行exe文件解决办法。 狼
    给Ubuntu右键快捷菜单添加终端栏目
    VC 单文档程序 隐藏程序及任务栏图标
  • 原文地址:https://www.cnblogs.com/fangnianqin/p/11429457.html
Copyright © 2020-2023  润新知