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

main.vue

  1. <template>
  2. <!--valuenow当前的评分 valuetext当前显示的文本-->
  3. <div
  4. class="el-rate"
  5. @keydown="handleKey"
  6. role="slider"
  7. :aria-valuenow="currentValue"
  8. :aria-valuetext="text"
  9. aria-valuemin="0"
  10. :aria-valuemax="max"
  11. tabindex="0">
  12. <!--包裹每个星的标签-->
  13. <span
  14. v-for="(item, key) in max"
  15. class="el-rate__item"
  16. @mousemove="setCurrentValue(item, $event)"
  17. @mouseleave="resetCurrentValue"
  18. @click="selectValue(item)"
  19. :style="{ cursor: rateDisabled ? 'auto' : 'pointer' }"
  20. :key="key">
  21. <!--显示评星的标签-->
  22. <i :class="[classes[item - 1], { 'hover': hoverIndex === item }]"
  23. class="el-rate__icon"
  24. :style="getIconStyle(item)">
  25. <!--这里主要是当评分出现小数,显示左边高亮的半星-->
  26. <i v-if="showDecimalIcon(item)"
  27. :class="decimalIconClass"
  28. :style="decimalStyle"
  29. class="el-rate__decimal">
  30. </i>
  31. </i>
  32. </span>
  33. <!--showText是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容;showScore是否显示当前分数,show-score 和 show-text 不能同时为真-->
  34. <span v-if="showText || showScore" class="el-rate__text" :style="{ color: textColor }">{{ text }}</span>
  35. </div>
  36. </template>
  37. <script>
  38. import { hasClass } from 'element-ui/src/utils/dom';
  39. import Migrating from 'element-ui/src/mixins/migrating';
  40. export default {
  41. name: 'ElRate',
  42. mixins: [Migrating],
  43. //provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。
  44. inject: {
  45. elForm: {
  46. default: ''
  47. }
  48. },
  49. data() {
  50. return {
  51. pointerAtLeftHalf: true,
  52. currentValue: this.value,
  53. hoverIndex: -1
  54. };
  55. },
  56. props: {
  57. value: {
  58. type: Number,
  59. default: 0
  60. },
  61. lowThreshold: { //低分和中等分数的界限值,值本身被划分在低分中
  62. type: Number,
  63. default: 2
  64. },
  65. highThreshold: { //高分和中等分数的界限值,值本身被划分在高分中
  66. type: Number,
  67. default: 4
  68. },
  69. max: { //最大分值
  70. type: Number,
  71. default: 5
  72. },
  73. colors: { //icon 的颜色数组,共有 3 个元素,为 3 个分段所对应的颜色
  74. type: Array,
  75. default() {
  76. return ['#F7BA2A', '#F7BA2A', '#F7BA2A'];
  77. }
  78. },
  79. voidColor: { //未选中 icon 的颜色
  80. type: String,
  81. default: '#C6D1DE'
  82. },
  83. disabledVoidColor: { //只读时未选中 icon 的颜色
  84. type: String,
  85. default: '#EFF2F7'
  86. },
  87. iconClasses: { //icon 的类名数组,共有 3 个元素,为 3 个分段所对应的类名
  88. type: Array,
  89. default() {
  90. return ['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on'];
  91. }
  92. },
  93. voidIconClass: { //未选中 icon 的类名
  94. type: String,
  95. default: 'el-icon-star-off'
  96. },
  97. disabledVoidIconClass: { //只读时未选中 icon 的类名
  98. type: String,
  99. default: 'el-icon-star-on'
  100. },
  101. disabled: { //是否为只读
  102. type: Boolean,
  103. default: false
  104. },
  105. allowHalf: { //是否允许半选
  106. type: Boolean,
  107. default: false
  108. },
  109. showText: { //是否显示辅助文字,若为真,则会从 texts 数组中选取当前分数对应的文字内容
  110. type: Boolean,
  111. default: false
  112. },
  113. showScore: { //是否显示当前分数,show-score 和 show-text 不能同时为真
  114. type: Boolean,
  115. default: false
  116. },
  117. textColor: { //辅助文字的颜色
  118. type: String,
  119. default: '#1f2d3d'
  120. },
  121. texts: { //辅助文字数组
  122. type: Array,
  123. default() {
  124. return ['极差', '失望', '一般', '满意', '惊喜'];
  125. }
  126. },
  127. scoreTemplate: { //分数显示模板
  128. type: String,
  129. default: '{value}'
  130. }
  131. },
  132. computed: {
  133. text() {
  134. let result = '';
  135. //如果显示当前分数
  136. if (this.showScore) {
  137. //如果当前是只读状态,就显示v-model绑定的值,否则根据用户的评分显示值
  138. result = this.scoreTemplate.replace(/\{\s*value\s*\}/, this.rateDisabled
  139. ? this.value
  140. : this.currentValue);
  141. } else if (this.showText) { //如果显示辅助文字,则根据用户设置评分currentValue来显示texts数组中的文字
  142. result = this.texts[Math.ceil(this.currentValue) - 1];
  143. }
  144. return result;
  145. },
  146. //高亮半星时添加的样式,颜色以及宽度
  147. decimalStyle() {
  148. let width = '';
  149. if (this.rateDisabled) {
  150. //这里判断value的值是否含有小数,有小数的则这里宽度为50%,为整数的话为0%
  151. width = `${ this.valueDecimal < 50 ? 0 : 50 }%`;
  152. }
  153. if (this.allowHalf) {
  154. width = '50%';
  155. }
  156. return {
  157. color: this.activeColor,
  158. width
  159. };
  160. },
  161. valueDecimal() {
  162. return this.value * 100 - Math.floor(this.value) * 100;
  163. },
  164. decimalIconClass() {
  165. return this.getValueFromMap(this.value, this.classMap);
  166. },
  167. voidClass() {
  168. return this.rateDisabled ? this.classMap.disabledVoidClass : this.classMap.voidClass;
  169. },
  170. //根据currentValue的分所在的等级,返回对应的类名
  171. activeClass() {
  172. return this.getValueFromMap(this.currentValue, this.classMap);
  173. },
  174. colorMap() {
  175. return {
  176. lowColor: this.colors[0],
  177. mediumColor: this.colors[1],
  178. highColor: this.colors[2],
  179. voidColor: this.voidColor,
  180. disabledVoidColor: this.disabledVoidColor
  181. };
  182. },
  183. //根据currentValue的分所在的等级,返回对应的颜色
  184. activeColor() {
  185. return this.getValueFromMap(this.currentValue, this.colorMap);
  186. },
  187. //这里主要是判断该星是选中还是未选中,分别加入选中和未选中icon类名
  188. classes() {
  189. let result = [];
  190. let i = 0;
  191. let threshold = this.currentValue;
  192. if (this.allowHalf && this.currentValue !== Math.floor(this.currentValue)) {
  193. threshold--;
  194. }
  195. for (; i < threshold; i++) {
  196. result.push(this.activeClass);
  197. }
  198. for (; i < this.max; i++) {
  199. result.push(this.voidClass);
  200. }
  201. return result;
  202. },
  203. classMap() {
  204. return {
  205. lowClass: this.iconClasses[0],
  206. mediumClass: this.iconClasses[1],
  207. highClass: this.iconClasses[2],
  208. voidClass: this.voidIconClass,
  209. disabledVoidClass: this.disabledVoidIconClass
  210. };
  211. },
  212. rateDisabled() {
  213. //是否为只读,或者父组件el-form中disabled的属性值,disabled是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效
  214. return this.disabled || (this.elForm || {}).disabled;
  215. }
  216. },
  217. watch: {
  218. value(val) {
  219. this.currentValue = val;
  220. this.pointerAtLeftHalf = this.value !== Math.floor(this.value);
  221. }
  222. },
  223. methods: {
  224. getMigratingConfig() {
  225. return {
  226. props: {
  227. 'text-template': 'text-template is renamed to score-template.'
  228. }
  229. };
  230. },
  231. //判断当前value在属于低分、中等分、高分中的哪个,根据不同等级返回不同的类名或者颜色
  232. getValueFromMap(value, map) {
  233. let result = '';
  234. if (value <= this.lowThreshold) {
  235. result = map.lowColor || map.lowClass;
  236. } else if (value >= this.highThreshold) {
  237. result = map.highColor || map.highClass;
  238. } else {
  239. result = map.mediumColor || map.mediumClass;
  240. }
  241. return result;
  242. },
  243. showDecimalIcon(item) {
  244. //如果当前value包含小数,并且item - 1 < this.value <item, showWhenDisabled为true
  245. let showWhenDisabled = this.rateDisabled && this.valueDecimal > 0 && item - 1 < this.value && item > this.value;
  246. //这里主要也是判断是否当前星是否应显示半星
  247. let showWhenAllowHalf = this.allowHalf &&
  248. this.pointerAtLeftHalf &&
  249. item - 0.5 <= this.currentValue &&
  250. item > this.currentValue;
  251. return showWhenDisabled || showWhenAllowHalf;
  252. },
  253. //返回当前星图标的颜色
  254. getIconStyle(item) {
  255. //voidColor的值是根据是否只读来判断返回disabled-void-color或者void-color
  256. const voidColor = this.rateDisabled ? this.colorMap.disabledVoidColor : this.colorMap.voidColor;
  257. return {
  258. //判断当前星是显示高亮的颜色还是未选中时的颜色
  259. color: item <= this.currentValue ? this.activeColor : voidColor
  260. };
  261. },
  262. //点击时设置值
  263. selectValue(value) {
  264. if (this.rateDisabled) {
  265. return;
  266. }
  267. //当可以显示半星时,这块传递的值为currentValue(鼠标移上去时会计算是否超过一半)
  268. if (this.allowHalf && this.pointerAtLeftHalf) {
  269. this.$emit('input', this.currentValue);
  270. this.$emit('change', this.currentValue);
  271. } else { //当不显示半星直接返回value
  272. this.$emit('input', value);
  273. this.$emit('change', value);
  274. }
  275. },
  276. //当按键按下时所调用的方法
  277. handleKey(e) {
  278. //如果组件被禁用则按键事件无效
  279. if (this.rateDisabled) {
  280. return;
  281. }
  282. let currentValue = this.currentValue;
  283. const keyCode = e.keyCode;
  284. //当按上下左右键的时候,允许半选则在currentValue加或减0.5,不允许则加或减1
  285. if (keyCode === 38 || keyCode === 39) { // up / right
  286. if (this.allowHalf) {
  287. currentValue += 0.5;
  288. } else {
  289. currentValue += 1;
  290. }
  291. e.stopPropagation();
  292. e.preventDefault();
  293. } else if (keyCode === 37 || keyCode === 40) { // left /down
  294. if (this.allowHalf) {
  295. currentValue -= 0.5;
  296. } else {
  297. currentValue -= 1;
  298. }
  299. e.stopPropagation();
  300. e.preventDefault();
  301. }
  302. currentValue = currentValue < 0 ? 0 : currentValue;
  303. currentValue = currentValue > this.max ? this.max : currentValue;
  304. //将currentValue通过input传递给子组件绑定的v-model值,触发change事件,子组件可以change在获取改变后的值
  305. this.$emit('input', currentValue);
  306. this.$emit('change', currentValue);
  307. },
  308. //鼠标移动时改变评星的值
  309. setCurrentValue(value, event) {
  310. if (this.rateDisabled) {
  311. return;
  312. }
  313. /* istanbul ignore if */
  314. if (this.allowHalf) {
  315. let target = event.target;
  316. //鼠标移动到包裹星星图标的span标签时,获取到显示星的icon标签
  317. if (hasClass(target, 'el-rate__item')) {
  318. target = target.querySelector('.el-rate__icon');
  319. }
  320. if (hasClass(target, 'el-rate__decimal')) {
  321. target = target.parentNode;
  322. }
  323. //根据鼠标移到一颗星的左边一半以内的位置,则减去当前值的0.5,否则就是等于当前值
  324. this.pointerAtLeftHalf = event.offsetX * 2 <= target.clientWidth;
  325. this.currentValue = this.pointerAtLeftHalf ? value - 0.5 : value;
  326. } else {
  327. //不允许半选时,鼠标移到那颗星就等于当前的值
  328. this.currentValue = value;
  329. }
  330. //记录鼠标移动的位置
  331. this.hoverIndex = value;
  332. },
  333. //鼠标移出时设置当前的值
  334. resetCurrentValue() {
  335. if (this.rateDisabled) {
  336. return;
  337. }
  338. if (this.allowHalf) {
  339. //如果当前的value是小数,pointerAtLeftHalf为true,如果是整数则为false,这里主要是为了点击时用来判断传哪个值
  340. this.pointerAtLeftHalf = this.value !== Math.floor(this.value);
  341. }
  342. //鼠标移上去时currentValue会改变,移走时currentValue等于之前的value
  343. this.currentValue = this.value;
  344. this.hoverIndex = -1;
  345. }
  346. },
  347. created() {
  348. if (!this.value) {
  349. this.$emit('input', 0);
  350. }
  351. }
  352. };
  353. </script>

element-ui Rate组件源码分析整理笔记(十三)的更多相关文章

  1. element-ui 组件源码分析整理笔记目录

    element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...

  2. element-ui button组件 radio组件源码分析整理笔记(一)

    Button组件 button.vue <template> <button class="el-button" @click="handleClick ...

  3. element-ui input组件源码分析整理笔记(六)

    input 输入框组件 源码: <template> <div :class="[ type === 'textarea' ? 'el-textarea' : 'el-in ...

  4. element-ui MessageBox组件源码分析整理笔记(十二)

    MessageBox组件源码,有添加部分注释 main.vue <template> <transition name="msgbox-fade"> < ...

  5. element-ui Message组件源码分析整理笔记(八)

    Message组件源码: main.js import Vue from 'vue'; import Main from './main.vue'; import { PopupManager } f ...

  6. element-ui Steps步骤条组件源码分析整理笔记(九)

    Steps步骤条组件源码: steps.vue <template> <!--设置 simple 可应用简洁风格,该条件下 align-center / description / ...

  7. Element UI table组件源码分析

    本文章从如下图所示的最基本的table入手,分析table组件源代码.本人已经对table组件原来的源码进行削减,源码点击这里下载.本文只对重要的代码片段进行讲解,推荐下载代码把项目运行起来,跟着文章 ...

  8. element-ui inputNumber、Card 、Breadcrumb组件源码分析整理笔记(三)

    inputNumber组件 <template> <!--@dragstart.prevent禁止input中数字的拖动--> <div @dragstart.preve ...

  9. element-ui Upload 上传组件源码分析整理笔记(十四)

    简单写了部分注释,upload-dragger.vue(拖拽上传时显示此组件).upload-list.vue(已上传文件列表)源码暂未添加多少注释,等有空再补充,先记下来... index.vue ...

随机推荐

  1. 上传App Store 被拒问题及解决方案总结

    最近公司比较忙,一直忙着写代码做新的应用,一连上线了几个应用,我们也是忙得焦头烂额的,都没时间做总结,今天趁APP审核期间,总结一下近期上传App Store遇到的一些问题和解决方法,以便以后查阅. ...

  2. Android应用打开外部文件

    我们有时候遇到要打开一个文件,我们可以选择用其他应用打开,这时弹出来的应用列表,那么我们如何让自己开发的应用也能出现在里面呢? 第一步:设置启动Activity的intent-filter,给data ...

  3. 爬虫---lxml爬取博客文章

    上一篇大概写了下lxml的用法,今天我们通过案例来实践,爬取我的博客博客并保存在本地 爬取博客园博客 爬取思路: 1.首先找到需要爬取的博客园地址 2.解析博客园地址 # coding:utf-8 i ...

  4. VLAN实验(5)三层交换

    1.选择1台S5700和3台pc机,并根据实验编址完成此拓扑图. 2.检查连通性 (1)因为mengyu-PC1和mengyu-PC2在一个地址段上,可以ping通 (2)因为mengyu-PC1和m ...

  5. 201271050130-滕江南-《面向对象程序设计(java)》第十三周学习总结

      201271050130-滕江南-<面向对象程序设计(java)>第十三周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daiz ...

  6. web之ics-06

    打开网址,四处点击,点到报表中心,跳转新页面 查看源码也没有什么特别的,发现URL栏有?id=1 以为是sql注入,但是并不是,查看大佬的wp 发现这题采用brupsuite爆破 先将抓到的包放到In ...

  7. React内容

    React Fiber   16版本 registerServiceWorker 的作用 PWA  progressive web application  写手机app应用   在断网的情况下,第二 ...

  8. MySQL实战45讲学习笔记:第十五讲

    一.引子 在今天这篇答疑文章更新前,MySQL 实战这个专栏已经更新了 14 篇.在这些文章中,大家在评论区留下了很多高质量的留言.现在,每篇文章的评论区都有热心的同学帮忙总结文章知识点,也有不少同学 ...

  9. Spring Security OAuth2学习

    什么是 oAuth oAuth 协议为用户资源的授权提供了一个安全的.开放而又简易的标准.与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需 ...

  10. 如何编写一个 SendFile 服务器

    如何编写一个 SendFile 服务器 前言 之前讨论零拷贝的时候,我们知道,两台机器之间传输文件,最快的方式就是 send file,众所周知,在 Java 中,该技术对应的则是 FileChann ...