关于javascript:VUE-实现超简单星级展示选择组件

37次阅读

共计 5696 个字符,预计需要花费 15 分钟才能阅读完成。

星级展现应该是个挺常见的需要,刚好我的项目中有碰到。所以分享一下实现的过程,不便当前复用

一、需要剖析

先看个常见的星级展现 UI

剖析组件须要的参数

属性 含意 默认值 类型
value 以后星级 4.5 Number
maxValue 总星级 5 Number
activeColor 星级色彩 #ff7e28 String

先看「以后星级」这个参数,思考到有小数。所以不能用半星、全星之类的简略办法。
图示里的 4.3 示意前 4 个星星都齐全展现,最初一个展现宽度的 0.3。所以咱们构建一个父子关系,让高亮局部的宽度,按父元素宽度的百分比展现即可

为了管制「星级色彩」,倡议用 svg 或者 font-icon(用图片也能够,多加两个参数传 activeImageplaceholderImage 就行)

二、筹备图标

先找个星星图标。我是在 iconfont 上找的。过程不赘述了,间接帖代码

/* icon-star.css */
@font-face {
  font-family: "iconfont";
  src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALcAAsAAAAABogAAAKNAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGVgCCcAqBCIERATYCJAMICwYABCAFhGcHMhvFBci+QDaGA61+ohmjWdUpRTi3djdG3vv+AydFVwwi+NoP3Xd3AQDFIBMXDWjjomJJRrYKAHVlJ7a6QkUXbf2//7U2h1mHNAnaykXU02lemf9XdHawZqFapfEojUazRCPehY40QHws1yy4q+8HVWZx/WBKLK7PSs3l5Ym0eW581PWGkt85n+dyfAvogNYHsbtrbRprc9Q7oPJAOtDmtrEIe5En3jB2wQu8RKDRklUDm7vHLZg5dSSDOUPs3iBrjNNQOzDGo4oCC/VCbcPKIv5Dup0C7kSfj3/qMUZSk9ktOyc7Pry84IzJl9Wl5RuXy4WBrZExBxTioDG7ZVAwdlBjdsgIOFZj8FNVBR5xVKdgf51d3wyGYS74yZMftZDgsQaaAtYmtRBTte963PSzq+7WbZR++rG3cy+5z8/7ug/25y+g4Qk+6Mun4R/12ePXZ5/6/npxvuf7/kj6LfYsJntdN/3Irfrfx5TpT9GwDlCVHzMCwVs+PGb9sckCbrpfR+GqAsP81O/cG/wks4EdxVBsdyqa1NidTJ3c0OgkqNjBTt9TbV13VAz1uib46wxlyOqNEIWZQY0mK6hVbwONZu2sb9KlMChKAybcAIR2z0hafUPW7pUozBdq9OqjVrt/NDqKlt2aTIS3xeQI+eheYOjlmXKtEmltkD5JHK5LdYirECbQNqxyYY8y4jnmVKe6LqJQcZ7iLj2PkiTHgvOIPDECkWLRNFXTWwwvT2ELIw5BfMh1AYU8uYwK1KX4fQ1EO5Fw8ECik2WVEGpHNoM1gNgzZYPaHmSfyimtTggFKQzyKbTLh5FEIoeK5mER4hGGYEK6sMh01NRQk7G9Jf21fdDItqdwKrP6yzDTnhMAAAAA') format('woff2')
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-star:before {content: "\e627";}

新建一个 icon-star.css 文件,把代码帖进去。vue 文件引入之后,在任意标签上加两个属性,就能够展现出咱们须要的「星星」了

<template>
    <div class="iconfont icon-star"> 星星 </div>
</template>

<script>
import "./icon-star.css";
 
export default {}
</script>

三、代码编写

先实现一个能够展现指定宽度的星星

<template>
  <div>
    <div class="iconfont icon-star star-item star-placeholder">
      <div
        class="iconfont icon-star star-item star-active"
        :style="{width:'60%'}"
      />
    </div>
    星星
  </div>
</template>

<script>
export default {};
</script>


<style scoped>
@font-face {
  font-family: "iconfont";
  src: url("data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAALcAAsAAAAABogAAAKNAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGVgCCcAqBCIERATYCJAMICwYABCAFhGcHMhvFBci+QDaGA61+ohmjWdUpRTi3djdG3vv+AydFVwwi+NoP3Xd3AQDFIBMXDWjjomJJRrYKAHVlJ7a6QkUXbf2//7U2h1mHNAnaykXU02lemf9XdHawZqFapfEojUazRCPehY40QHws1yy4q+8HVWZx/WBKLK7PSs3l5Ym0eW581PWGkt85n+dyfAvogNYHsbtrbRprc9Q7oPJAOtDmtrEIe5En3jB2wQu8RKDRklUDm7vHLZg5dSSDOUPs3iBrjNNQOzDGo4oCC/VCbcPKIv5Dup0C7kSfj3/qMUZSk9ktOyc7Pry84IzJl9Wl5RuXy4WBrZExBxTioDG7ZVAwdlBjdsgIOFZj8FNVBR5xVKdgf51d3wyGYS74yZMftZDgsQaaAtYmtRBTte963PSzq+7WbZR++rG3cy+5z8/7ug/25y+g4Qk+6Mun4R/12ePXZ5/6/npxvuf7/kj6LfYsJntdN/3Irfrfx5TpT9GwDlCVHzMCwVs+PGb9sckCbrpfR+GqAsP81O/cG/wks4EdxVBsdyqa1NidTJ3c0OgkqNjBTt9TbV13VAz1uib46wxlyOqNEIWZQY0mK6hVbwONZu2sb9KlMChKAybcAIR2z0hafUPW7pUozBdq9OqjVrt/NDqKlt2aTIS3xeQI+eheYOjlmXKtEmltkD5JHK5LdYirECbQNqxyYY8y4jnmVKe6LqJQcZ7iLj2PkiTHgvOIPDECkWLRNFXTWwwvT2ELIw5BfMh1AYU8uYwK1KX4fQ1EO5Fw8ECik2WVEGpHNoM1gNgzZYPaHmSfyimtTggFKQzyKbTLh5FEIoeK5mER4hGGYEK6sMh01NRQk7G9Jf21fdDItqdwKrP6yzDTnhMAAAAA")
    format("woff2");
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-star:before {content: "\e627";}

.star-item {
  display: inline-block;
  font-size: 40px;
}

.star-placeholder {position: relative;}
.star-active {
  position: absolute;
  top: 0;
  left: 0;
  color: red;
  overflow: hidden;
}
</style>

再加个循环,并计算每个 star-item 该展现的宽度。最终代码如下:

<template>
  <div>
    <div
      v-for="index in maxValue"
      :key="index"
      class="iconfont icon-star star-item star-placeholder"
    >
      <div
        class="iconfont icon-star star-item star-active"
        :style="{width: getWidth(index), color: activeColor }"
      />
    </div>
    <span class="star-value">
      {{starValue}}
    </span>
  </div>
</template>

<script>
import "./icon-star.css";

export default {
  props: {
    maxValue: {
      type: Number,
      default: 5,
    },
    value: {
      type: Number,
      default: 4.5,
    },
    activeColor: {
      type: String,
      default: "#ff7e28",
    },
  },
  computed: {starValue() {return this.value.toFixed(1);
    },
  },
  methods: {getWidth(index) {
      const gap = this.value - index + 1;
      if (gap >= 1) {return "100%";} else if (gap <= 0) {return 0;} else {return gap * 100 + "%";}
    },
  },
};
</script>


<style scoped>
.star-item {
  display: inline-block;
  font-size: 40px;
}

.star-placeholder {
  position: relative;
  color: #e9e9e9;
}
.star-active {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
}
.star-value {
  font-size: 40px;
  margin-left: 10px;
}
</style>

四、成果展现

  <star-level :value="4.1" />
  <star-level :value="3" activeColor="blue" />
  <star-level :value="8.8" :maxValue="10" activeColor="green" />

五、抉择星级

既然展现都做进去了,不如再略微改改,做个抉择星级的组件

思路就是判断鼠标在以后星级的地位,并联合这是第几颗星,计算出 value 值

<template>
  <div>
    <div
      v-for="index in maxValue"
      :key="index"
      @mousemove="mousemoveStarItem($event, index)"
      class="iconfont icon-star star-item star-placeholder"
    >
      <div
        class="iconfont icon-star star-item star-active"
        :style="{width: getWidth(index), color: activeColor }"
      />
    </div>
    <span class="star-value" :style="{color: activeColor}">
      {{starValue}}
    </span>
  </div>
</template>

<script>
import "./icon-star.css";

export default {data() {
    return {value: 0,};
  },
  props: {
    maxValue: {
      type: Number,
      default: 5,
    },
    activeColor: {
      type: String,
      default: "#ff7e28",
    },
  },
  computed: {starValue() {return this.value.toFixed(1);
    },
  },
  methods: {getWidth(index) {
      const gap = this.value - index + 1;
      if (gap >= 1) {return "100%";} else if (gap <= 0) {return 0;} else {return gap * 100 + "%";}
    },
    mousemoveStarItem(e, index) {
      const width = e.currentTarget.offsetWidth;
      this.value = index + e.offsetX / width - 1;
    },
  },
};
</script>


<style scoped>
.star-item {
  display: inline-block;
  font-size: 40px;
}

.star-placeholder {
  cursor: pointer;
  position: relative;
  color: #e9e9e9;
}
.star-active {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
}
.star-value {
  font-size: 40px;
  margin-left: 10px;
}
</style>

附录:

CodeSandBox 代码示例:https://codesandbox.io/s/star…

正文完
 0