WeChat applet-star rating component (supports half-star/custom size)

Although the scoring component directly copied from the Internet can be used, the rendering of the component I found is slightly worse, so I am going to improve it myself.

Put a rendering first:

 

1. Preparation

Prepare four similar pictures. The pictures must be cut in half accurately according to the pixels , otherwise there will be overlap in the applet.

It is recommended to choose the icon you want in the iconfont icon library , download it locally and use [Paint 3D] to cut the picture in half.

Example images are as follows:

        


2. Components

        The wxss part of the code is borrowed from the reference article , but its JS rendering part is improved.

        [Explanation]: The default score of this component is 1 point, the minimum score is 0.5 points, and 0 points are not supported. You can change the flag1, flag2 and star_num in the stars array of the JS file to customize the score.

        Create a new component in the WeChat developer tool, this time the example is named star

        1.star.js

           【bgImgL】corresponds to the unselected left half-star image path

           【bgfImgL】corresponds to the path of the selected left half-star image

           【bgImgR】Corresponding to the unselected right half-star image path

           【bgfImgR】corresponds to the path of the selected right half-star image

             Please replace the above four image paths with local image paths

// components/star.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    //接收自定义的高度
    setSize:Number,
  },

  data: {
    stars: [
      {
        flag1: 2,
        flag2: 2,
        bgImgL: "/src/icons/Lstar.png",
        bgfImgL: "/src/icons/Lstar.active.png",
        bgImgR: "/src/icons/Rstar.png",
        bgfImgR: "/src/icons/Rstar.active.png",
      },
      {
        flag1: 1,
        flag2: 1,
        bgImgL: "/src/icons/Lstar.png",
        bgfImgL: "/src/icons/Lstar.active.png",
        bgImgR: "/src/icons/Rstar.png",
        bgfImgR: "/src/icons/Rstar.active.png",
      },
      {
        flag1: 1,
        flag2: 1,
        bgImgL: "/src/icons/Lstar.png",
        bgfImgL: "/src/icons/Lstar.active.png",
        bgImgR: "/src/icons/Rstar.png",
        bgfImgR: "/src/icons/Rstar.active.png",
      },
      {
        flag1: 1,
        flag2: 1,
        bgImgL: "/src/icons/Lstar.png",
        bgfImgL: "/src/icons/Lstar.active.png",
        bgImgR: "/src/icons/Rstar.png",
        bgfImgR: "/src/icons/Rstar.active.png",
      },
      {
        flag1:1,
        flag2:1,
        bgImgL: "/src/icons/Lstar.png",
        bgfImgL: "/src/icons/Lstar.active.png",
        bgImgR: "/src/icons/Rstar.png",
        bgfImgR: "/src/icons/Rstar.active.png",
      },
      
    ],
    star_num: 1,  // 默认1分  最低0.5分
    Lindex:0,  //左下标
    Rindex:0,   //右下标 
    oldScore:'', //旧分数
    newScore:''//新分数
  },

  /**
   * 组件的方法列表
   */
  methods: {
      //点击左边
    scoreL: function (e) {
      var _this = this;
      this.setData({
        oldScore:this.data.star_num
      })
      // console.log("旧分数",this.data.oldScore)
      var index = e.currentTarget.dataset.index;
      //改变分数
      _this.setData({
        star_num: index + 0.5 // 评分
      })
      this.setData({
        newScore:this.data.star_num
      })
      // console.log("新分数",this.data.newScore)
      this.judgeNum() //重新渲染星星
    },
    //点击右边
    scoreR: function (e) {
      this.setData({
        oldScore:this.data.star_num
      })
      var _this = this;
      var index = e.currentTarget.dataset.index;
      // 评分
      _this.setData({
        star_num: index + 1 // 评分
      })
      this.setData({
        newScore:this.data.star_num
      })
      this.judgeNum()
    },
    changeL(param){     //左移  1代表减 2代表加
      var that = this;
      // console.log("LL左下标",that.data.Lindex)
      // console.log("LL右下标",that.data.Rindex)
      var item ='stars['+that.data.Lindex+'].flag1'
      if(param===1){ //左移动
        // console.log("锚点1")
        const middle = that.data.Lindex 
        var item ='stars['+middle+'].flag1'
        that.setData({
          [item]:1,
          Lindex:that.data.Lindex-1
        })
      }
      if(param===2){
        // console.log("锚点2")
        const middle = that.data.Lindex + 1
        var item ='stars['+middle+'].flag1'
        that.setData({
          [item]:2,
          Lindex:that.data.Lindex+1
        })
      }
    },
    changeR(param){    //右移  1代表减 2代表加
      const that = this
      var item ='stars['+that.data.Lindex+'].flag2'
      if(param===1){ //左移动
        // console.log("锚点3")
        that.setData({
          [item]:1,
          Rindex:this.data.Rindex-1
        })
      }
      if(param===2){
        // console.log("锚点4")
        const middle = that.data.Rindex + 1
        var item ='stars['+middle+'].flag2'
        that.setData({
          [item]:2,
          Rindex:this.data.Rindex+1
        })
      }
    },
    judgeNum:function(){
      const isPoint = (this.data.oldScore) % 1 ==0? false:true
      const flag = this.data.newScore - this.data.oldScore //分差
      if(flag<0)  {//分差小于0 扣分
        if(isPoint) {  //是小数(左)
          const LorR={
            toL:true,
            toR:false,
          }
          const count = Math.abs(flag)*2  //变化的次数 LRLR
          for (var i=0;i<count;i++)
          {
            if(LorR.toL){
              this.changeL(1)
            }
            if(LorR.toR){
              this.changeR(1)
            }
            LorR.toL=!LorR.toL
            LorR.toR=!LorR.toR
          }
        }//是整数(右)
        else{
          const LorR={
            toL:false,
            toR:true,
          }
          const count = Math.abs(flag)*2  //变化的次数 LRLR
          for (var i=0;i<count;i++)
          {
            if(LorR.toL){
              this.changeL(1)
            }
            if(LorR.toR){
              this.changeR(1)
            }
            LorR.toL=!LorR.toL
            LorR.toR=!LorR.toR
          }
        }
      }  //分差大于0 加分
      else{
        if(isPoint) {//是小数
        const LorR={
          toL:false,
          toR:true,
        }
        const count = Math.abs(flag)*2  //变化的次数 LRLR
        for (var i=0;i<count;i++)
        {
          if(LorR.toL){
            this.changeL(2)
          }
          if(LorR.toR){
            this.changeR(2)
          }
          LorR.toL=!LorR.toL
          LorR.toR=!LorR.toR
        }
        }
        else{ //是整数
          const LorR={
            toL:true,
            toR:false,
          }
          const count = Math.abs(flag)*2  //变化的次数 LRLR
          for (var i=0;i<count;i++)
          {
            if(LorR.toL){
              this.changeL(2)
            }
            if(LorR.toR){
              this.changeR(2)
            }
            LorR.toL=!LorR.toL
            LorR.toR=!LorR.toR
          }
        }
     }
    },
    setNum(){  //向父组件传值
      //传入的参数名称 starNum    
      this.triggerEvent('myevent',{starNum:this.data.star_num})
    }
  }
})

        2.star.wxml

<view class="stars" bindtap="setNum">
  <view wx:for="{
   
   {stars}}" wx:key="index" class="starItem" style="--width--:{
   
   {setSize}}rpx;--height--:{
   
   {setSize}}rpx">
    <image src="{
   
   {item.flag1 == 1 ? item.bgImgL : item.bgfImgL}}" data-index="{
   
   {index}}" bindtap='scoreL'>
    </image>
    <image src="{
   
   {item.flag2 == 1 ? item.bgImgR : item.bgfImgR}}" data-index="{
   
   {index}}" bindtap='scoreR'></image>
  </view>
</view>

        3.star.wxss

.stars {
  display: flex;
  width: var(--width--);
  height: var(--height--);
  /* width: 100%;
  height: 100px; */
}

.stars view {
  position: relative;
  width: var(--width--);
  height: var(--height--);
  margin-right: 20rpx;
}

.stars view image:nth-of-type(1) {
  width: 50%;
  height: 100%;
  margin-right: -2rpx;
}
.stars view image:nth-of-type(2) {
  width: 50%;
  height: 100%;
  margin-left: -1rpx;
}

3. Reference in the page

This component supports custom height, so when referencing this component in other pages, you need to pass in a parameter to set its width and height, the size is rpx, and the name of the parameter passed in is [setSize], and this component supports setting The rating for is returned to the page that introduced the component.

        1. Import the json file of the page

        Please replace the position of the component with the position of your own component, which is only a sample code

{
  "usingComponents": {
    "star":"../../../components/star/star"
  }
}

        2. Import the wxml file of the page

//setSize=100 表示将组件的高度设置为100rpx  
//bind:myevent =“setStarNum”用于接收子组件回传的评分数值
//需在JS文件中写一个【setStarNum】函数
<star setSize='100' bind:myevent="setStarNum"></star>

        3. Import the js file of the page

 
 setStarNum(e){
    console.log("获得的评分为",e.detail.starNum)
  },

  //评分已经拿到了,如何处理及操作可自行编写

  4. Effect demonstration

        The optimized rendering process will not have the problem of flickering stars in the original copy code. The actual change process is much smoother. Put the two pictures for comparison

        1. Optimized

         2. Not optimized

                Obvious stroboscopic phenomenon can be seen when switching. If you are interested, you can refer to the original article for reference. The flickering is caused by clearing the status of the original stars every time and not filling in order when re-rendering.

                                     

 

It is not easy to write, if there is a bug in the process of use, welcome to exchange and correct.

        

Guess you like

Origin blog.csdn.net/SCY164759920/article/details/126497648