第13集:从零开始实现一套PC端Vue的ui组件库(评分组件小星星)
时间:2023-03-31 11:38:02
CSS
第13集:从零开始实现一套PC端Vue的ui组件库(评分组件小星星)1.本集定位说到评分,我看到的第一个表格是电影网站,每部电影都有几颗星。后来有了用户手动选择星星打分的方法。这些方法更直观。更能吸引用户参与。这个组件的玩法其实有很多种。相对于加载动画,我可以用星星的持续发光来作为加载进度图。该组件的许多ui库使其非常固定。比如它只能是5星,而这次在写这个组件的时候,我的原则是星数可以有多少,当然也可以少多少,至少1个,最多无限。是不是很有趣?实现思路是因为我这里的图标组件是用svg实现的。最后我选择使用两行相同的图标组件,重叠在一起,然后改变顶层的宽度,达到选中区域颜色的效果。2.需求审核只读模式:只显示。选择方式:点击设置新分数,鼠标滑过时分数会发生变化。颜色和大小可以由用户设置。特点:可以设置“星星”总数。可以设置满分。您可以更换图形,绝对不仅仅是“星星”。必须兼容多层父组件的情况,以及多层父和父组件滚动偏移的情况。每次都可以以整颗星为单位选择星。3.基础构建先上传一个正常状态下的渲染vue-cc-ui/src/components/Rate/index.jsimportRatefrom'./main/rate.vue'Rate.install=function(Vue){Vue.component(Rate.name,Rate);};导出默认Ratevue-cc-ui/src/components/Rate/main/rate.vue
上面的num是指用户定义的星星数。总数是星星满的时候。相当于多少颗星props:{disabled:Boolean,//为true时不允许修改num:{//显示几颗星type:Number,default:5},total:{//总数ofpointstype:Number,default:5},size:{//starsizetype:Number,default:20},value:{//当前分数类型:[Number,String],required:true}}adddynamicsforcc-icon样式,这样它的宽度会随着我鼠标的位置而变化
//...计算如何显示methods:{//this.value是用户绑定的v-modleboundary(value){//如果小于boundary,就是最小值,如果大于边界,则为最大值if(value<=0)value=0;if(value>=this.numTotal)value=this.numTotal;返回值;}},computed:{width(){//当前要显示的值,相对于总分的比例!让proportion=this.boundary(this.value)/this.numTotal;//用这个比例换算,求出在对应的总宽度下应该是多宽return`${proportion*(this.size*this.num)}px`;}numTotal(){//传入的总分是否有效//如果小于0,总分将根据星数返回this.total<=0?this.num:这个。全部的;},}以上代码可以实现一个简单的评分组件。然后我们会做一些关于图标样式的文章。注意这个iconType是key这个词很重要,它决定了图标是什么样子的iconType(){//临时有用的属性定义为它们let{type,darkColor,brightColor}=this,//默认样式不能少result={name:type||“cc-stars2”,brightColor:brightColor||"rgb(247,186,42)",暗色:暗色||“#bbbbbb”};返回结果;}}如果选择动态加载图标,他还可以旋转4.鼠标移动与鼠标的交互说到鼠标滑到哪里,星选分数就会跟着到哪里1.onmouseleave,onmouseenter,鼠标进入指定元素区域触发事件,不支持冒泡,不包含子元素区域2、onmouseout、onmouseover、鼠标输入指定元素触发事件,包含子元素区域。handelMousemove比较核心代码(也增加了新的计算,接下来会说)handelMousemove(e){//实时判断的原因是用户现在可能禁止修改,以后不会禁止!!if(!this.disabled){//获取第i个标签的domletnode=this.$refs.box;//getHTMLScroll是之前封装的获取距离的方法(下一集会介绍新的方法)//鼠标到左边的距离,减去元素到左边的距离,就是鼠标到元素的距离元素左边距离//当前图标的大小*图标总数,也就是总图标的宽度//将上面的比例换算成总分中的分数;让值=((e.pageX-getHTMLScroll(node).left)/(this.size*this.num))*this.numTotal;//检查值;value=this.boundary(value);this.$emit("输入",值);}},离开functiondata(){return{oldVal:0};},方法:{handelMouseleave(){if(!this.disabled){this.$emit("input",this.oldVal);}},}oldVal上面我提到了这个变量,所以我举个例子说明一下,我去年才开始接触后台管理系统。很多页面布局在顶部有大量的查询条件和搜索框,下面是查询结果列表。然后遇到了问题。例如,用户通过条件a查询结果列表。当用户翻页时,用户根据条件a搜索下一页的列表,但是如果用户将条件a修改为条件b但没有点击再次搜索,而是点击翻页。这个时候我们还是要用条件a去查询下一页。页面显示的条件是b,所以可以看出每个条件后面都有两个变量,一个是显示的,一个是真正的查询条件。这次oldVal解决的问题和上面说的差不多。当用户鼠标悬停在组件上时,组件相应改变选中状态,即上图标的宽度,但用户没有做出选择,而不是离开图标元素,应该恢复图标的状态到原来的状态,这个状态值为oldVal。单击以更改选择状态。由于上面的逻辑和结构,这一步很简单。selectValue(){//更新,确保this.oldVal=this.value已经执行;//这个值其实是在滑动的时候计算出来的//这里是为了避免multi-v-model绑定可能出现的bugthis.$emit("change",this.oldVal);},上面我们已经完成了用户配置的处理,所以可以实现如下效果;满分已经可以设置为10分;数量可由您自行设定;5.显示分数和样式dom在结构上,只有当用户传入分数时,才会给用户显示我们的分数显示组件//...{{value|fix}}上面filter显示的数据用.0填充;其实也有缺点,会自动向上取整,根据情况使用;exportconstmyToFixed=value=>{value=value+'';如果(value.includes('.')){让sp=value.split('.');返回sp[0]+'.'+sp[1].slice(0,1);}else{返回值+'.0';}};每次都要选完成一颗星有时候用户不想要.1.2.3而是想要整数,所以每次都给用户返回整数就好了,所以不要忘记计算总分props:{one:Boolean,//只让每一个都完整}methods:{//计算手指的位置//在点击或移动时有效吗?handelMousemove(e){if(!this.disabled){让节点=this.$refs.box;让值=((e.pageX-getHTMLScroll(node).left)/(this.size*this.num))*this.numTotal;value=this.boundary(value);//新代码-------------------------------------//每个星星之间的距离mustbecompleteleti=0,//求某星对应的分数oneNum=this.numTotal/this.num;//直到它大于这个while(oneNum*i<=value){i++;}if(this.one){//防止溢出value=Math.min(oneNum*i,this.numTotal);this.$emit("输入",值);//新代码-----------------------------------------}else{this.$emit("输入",值);}}},}缩小效果被选中:如图,这个效果我的想法是给一个索引值,小于索引的都缩小。当然,用户需要开启大模式data(){return{oldVal:0,bigIndex:0};},methods:{//计算手指的位置//点击或移动时是否有效?handelMousemove(e){//实时判断的原因是用户现在可能禁止更改,后面需要更改!!if(!this.disabled){//...//之前的放大效果//每块之间的距离必须是完整的leti=0,oneNum=this.numTotal/this.num;while(oneNum*i<=value){i++;}//新代码------------if(this.big){//借花供佛,统计上面计算的星数,直接用this.bigIndex=i;}//新代码--------------if(this.one){//防止溢出value=Math.min(oneNum*i,this.numTotal)this.$emit("input“,价值);}else{this.$emit("输入",值);}}},}上面的i变量可以优化一下,因为不是每次都需要,毕竟用户产生1000颗星是有可能的;让我,oneNum;如果(this.big||this.one){i=0;oneNum=this.numTotal/this.num;while(oneNum*i<=value){i++;}if(this.big){this.bigIndex=i;}}if(this.one){//防止值溢出=Math.min(oneNum*i,this.numTotal);this.$emit("输入",值);}else{this.$emit("输入",值);}继续处理index//离开区域handelMouseleave(){//离开的时候当然要取消所有缩放效果this.bigIndex=0;如果(!this.disabled){this.$emit("input",this.oldVal);}},tailmounted(){//一开始就初始化oldValue;this.oldVal=this.value;}end我也服了,文章太长卡住了....下一章讲提示框组件popover大家可以一起交流,一起学习,一起进步,早日实现自我价值尽可能!工程github地址:github个人技术博客(组件官网):链接说明