element-ui Rate组件源码分析整理笔记(十三)
程序员文章站
2022-03-26 12:29:52
Rate组件源码比较简单,有添加部分注释 main.vue pythod
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>
下一篇: 简单layer 快速上手
推荐阅读
-
element-ui Upload 上传组件源码分析整理笔记(十四)
-
element-ui Tag、Dialog组件源码分析整理笔记(五)
-
element-ui button组件 radio组件源码分析整理笔记(一)
-
element-ui Carousel 走马灯源码分析整理笔记(十一)
-
element-ui Upload 上传组件源码分析整理笔记(十四)
-
element-ui input组件源码分析整理笔记(六)
-
element-ui Steps步骤条组件源码分析整理笔记(九)
-
element-ui switch组件源码分析整理笔记(二)
-
element-ui inputNumber、Card 、Breadcrumb组件源码分析整理笔记(三)
-
element-ui Rate组件源码分析整理笔记(十三)