星级展现应该是个挺常见的需要,刚好我的项目中有碰到。所以分享一下实现的过程,不便当前复用
一、需要剖析
先看个常见的星级展现 UI
剖析组件须要的参数
属性 | 含意 | 默认值 | 类型 |
---|---|---|---|
value | 以后星级 | 4.5 | Number |
maxValue | 总星级 | 5 | Number |
activeColor | 星级色彩 | #ff7e28 | String |
先看「以后星级」这个参数,思考到有小数。所以不能用半星、全星之类的简略办法。
图示里的 4.3
示意前 4 个星星都齐全展现,最初一个展现宽度的 0.3
。所以咱们构建一个父子关系,让高亮局部的宽度,按父元素宽度的百分比展现即可
为了管制「星级色彩」,倡议用 svg 或者 font-icon(用图片也能够,多加两个参数传 activeImage
、placeholderImage
就行)
二、筹备图标
先找个星星图标。我是在 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...