如何使用Vue封装星星评分组件

<template>
  <div>
    <div class="star mb-10" :class="starType">
        <span 
          class="star-item" 
          v-for = "(itemClass,i) in itemClassess" 
          :class="itemClass" 
          :key="i"
        ></span>
    </div>
  </div>
</template>

<script>
     const LENGTH = 10;//星星个数
     const CLS_ON = "on";//满星状态
     const CLS_HALF = "half";//半星状态
     const CLS_OFF = "off";//无星状态

    export default {
         props: {
            size: {
                type : Number//参数:尺寸
            },
            score: {
                type : Number//参数:评分
            }
         },
         computed: {
            starType(){//设置星星尺寸
                return "star-" + this.size;
            },
            itemClassess(){
                let result = [];//记录状态的数组
                let score = Math.floor(this.score * 2) / 2;
                let hasDecimal = score % 1 !==0;
                let integer = Math.floor(score);//向下取整
                //全星
                for(let i = 0; i < integer; i++){
                    result.push(CLS_ON);
                }
                //半星
                if(hasDecimal){
                    result.push(CLS_HALF);
                }
                //无星
                if(result.length < LENGTH){
                    result.push(CLS_OFF);
                }
                return result;
            }
         }
    }
</script>

<style>
    .star {
        display: flex;
        width: 100%;
    }
    .star-48 .star-item { 
        width: 20px;
        height: 20px;
        margin-right: 22px;
        background-repeat: no-repeat;
        background-size: 20px 20px;
    }
    .star-48 .star-item:last-child {
        margin-right: 0px;
    }
    .star-48 .star-item.on {
        background-image: url("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1264157627,2023353298&fm=26&gp=0.jpg");
    }
    .star-48 .star-item.half {
        background-image: url("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3837197790,4152490133&fm=15&gp=0.jpg");
    }
    .star-48 .star-item.off {
        background-image: url("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3377642465,2658946556&fm=26&gp=0.jpg");
    }

    .star-36 .star-item { 
        width: 15px;
        height: 15px;
        margin-right: 6px;
        background-repeat: no-repeat;
        background-size: 15px 15px;
    }
    .star-36 .star-item:last-child {
        margin-right: 0px;
    }
    .star-36 .star-item:last-child {
        margin-right: 0px;
    }
    .star-36 .star-item.on {
        background-image: url("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1264157627,2023353298&fm=26&gp=0.jpg");
    }
    .star-36 .star-item.half {
        background-image: url("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3837197790,4152490133&fm=15&gp=0.jpg");
    }
    .star-36 .star-item.off {
        background-image: url("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3377642465,2658946556&fm=26&gp=0.jpg");
    }
</style>

在使用的组件中调用

<Reta :size="48" :score="8.5"></Reta>

size :大小
score :几颗星

这是一种方法 是直接渲染后台返回的数据的

那么再写一种使用点击的方式,逻辑自定义

<template>
  <div class="star">
    <!-- // 用于父子组件双向绑定 -->
    <input type="hidden" v-model="value">
    <!-- // 不可点击的星星 -->
    <div v-if="readonly">
      <!-- // 满星 -->
      <img v-for="i in parseInt(value)" :key="i" :src="full">
      <!-- // 半星 -->
      <img v-if="value.toString().indexOf('.') > 0" :src="half">
      <!-- // 灰星 -->
      <img v-for="i in parseInt(number - value)" :key="i * number+1" :src="empty">
    </div>
    <!-- // 可点击的星星 -->
    <div v-if="!readonly">
      <!-- // 满星 -->
      <img v-for="i in num" :key="i" :src="full" @click="num = i">
      <!-- // 灰星 -->
      <img v-for="i in parseInt(number - num)" :key="i * number" :src="empty" @click="num += i">
    </div>
  </div>
</template>

<script>
export default {
  props: {
    // 分值
    value: {
      type: Number,
      default: 0
    },
    // 接收过来的数量
    number: {
      type: Number,
      default: 0
    },
    // 只读,表示可以点击还是不可点击
    readonly: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      num: 0,
      full:'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1264157627,2023353298&fm=26&gp=0.jpg', // 满星
      empty:'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3377642465,2658946556&fm=26&gp=0.jpg', // 没星
      half:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3837197790,4152490133&fm=15&gp=0.jpg' // 半星
    }
  },
  watch: {
    num () {
      // 可点击状态下,双向绑定的分值改变
      this.$emit('input', this.num)
    }
  }
}
</script>

<style scoped>
  .star img {
     width: 24px;
     height: 24px;
     margin: 0 2px;
   }
</style>

在使用的组件中直接调用

<template>
  <div>
		<span>评分</span>
		可点击
		<Reta v-model="value" :number="10" @input="inp"/>
		不可点击
		// <Reta v-model="value" :number="10" readonly />

		// 这两个一个可点击一个不可点击的最好别同时使用,不然影响操作,
		因为一个可以一个不可以 点击可以的那个参数跟着变化,那个不可点击的也会随着变化 这里只是一个参考作用

  </div>
</template>

<script>
import Reta from "@/components/reta"
import Bus from "../utils/Bus"
export default {
	components:{Toast},
	data(){
        return {
		  value:4.5
        }
	},
	methods:{
	// 点击过后多少星,返回过来,这里可以请求后台接口
		inp(num)
		{
			console.log(num)
			console.log("点击了"+num+'颗星星')
		}
	}
}
</script>

整体思路还是比较简单的,我封装的第1种评分使用场景是请求后台接口数据,返回的评分我们直接渲染就可以了
第2种应用场景呢就是比如你叫了个外卖,送餐人员给你送到,你给送餐人员评分,然后获取到评分的数,请求后台接口,
把评分数传给后台

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值