布局部分:
<div id="slider"> <!-- 主要动画效果:字体、进度条和表情随情绪百分比而变化 --> <label for="range" :style="{'color':getHappinessColor}">情绪程度: {
{val}}%</label> <!-- 滑动杆的颜色应与预设的颜色绑定,颜色可以随意更改 --> <!-- 情绪值也应随之而来val值变动 --> <input type="range" name="" id="range" min="0" max="100" v-model="val"> <!-- 滑杆值应与val绑定,val写入计算属性,与下滑杆填充颜色的范围同步 --> <div class="slider outer"> <!-- 让我们label 的宽度 等于数据中心 val 宽度会随着滑动杆的运动而驱动label 运动,达到改变表情的效果 --> <label for="" class="slider inner" :style="{'width':val '%', 'border-radius':greaterThanFifty}"> <span :style="{'right':getPlacement}">{
{getHappiness}}</span> </label> </div> </div>
样式部分:
*{ padding: 0; margin: 0; list-style: none; } :root { /* 全局css变量 */ --yellow: #ffd100; --orange: #ff6a13; --darkGray: #53565a; --midGray: #888b8d; --white: #fff; } *,*::after,*::before{ color: var(--darkGray); box-sizing: border-box; } html,body { width: 100%; height: 100%; } body{ min-height: 100vh; display: flex; justify-content: center; align-items: center; background-color: var(--white); } #slider{ /* 局部css变量 */ --roundness: 20px; width: 100%; max-width: 600px; outline: 1px dashed red; padding: 4vh; /* 网格布局 */ display: grid; justify-content: stretch; } #slider>label{ width: 100%; font-size: 1.5em; padding: 0 0 0.5em; margin: auto; } #slider input{ grid-row: 2 / 3; grid-column: 1 / 2; width: 100%; position: relative; z-index: 1; opacity: 0; height: calc(var(--roundness) * 2); cursor: pointer; } #slider .outer{ width: 100%; height: var(--roundness); background-color: var(--midGray); border-radius: var(--roundness); display: flex; align-items: center; align-content: center; position: relative; z-index: 0; margin: auto; grid-row: 2/3; grid-column: 1/2; } #slider input:focus .outer { outline: 1px dashed var(--orange); } #slider label.inner { position: absolute; width: 100%; height: 100%; background: var(--white); background: linear-gradient(to left, var(--yellow), var(--orange)); border-top-left-radius: var(--roundness) !important; border-bottom-left-radius: var(--roundness) !important; position: absolute; transition: all 0.3s cubic-bezier(0.5, 0.4, 0.2, 1); text-align: right; font-size: calc(var(--roundness) * 2); line-height: 1; } #slider label.inner span { position: absolute; right: -2px; top: calc(50% - var(--roundness) * 2); top: calc(var(--roundness) * -.3); transition: inherit; }
Vue 部分:
<script src="./js/vue.js"></script> <script> let a = new Vue({ el:"#slider", data() { return { val: 70, // 同时用于动态关联 1:情绪百分比,2:显示的文本表达 } }, mounted() { this.val = Math.floor(Math.random() * 101) }, computed: { getPlacement: function () { return `${(-0.009 * ((this.val * -1) 104))}em`; // 获取位置,因为是计算属性,相当于和val绑定,给底部span绑定后,等于与上面和上面绑定val绑定的width,绑定 }, greaterThanFifty: function () { return this.val > 50 ? `var(--roundness)` : `0`; // val值大于50后,边框的变化可以省略或不绑定,不重要 }, getHappinessColor: function () { return `rgba(255, ${106 (103 / 100 * this.val)}, ${(Math.floor(this.val * -1 / 7.692)) 13}`; // 获得颜色函数可以随意更改值,但上面的颜色过渡更自然 }, getHappiness: function () { let mood; // 将val值与所有表情“物理绑定” if (this.val == 0) { mood = "???" } else if (this.val < 10) { mood = "??" } else if (this.val < 20) { mood = "??" } else if (this.val < 30) { mood = "??" } else if (this.val < 40) { mood = "??" } else if (this.val < 50) { mood = "??" } else if (this.val < 60) { mood = "??" } else if (this.val < 70) { mood = "??" } else if (this.val < 80) { mood = "??" } else if (this.val < 90) { mood = "??" } else if (this.val < 100) { mood = "??" } else if (thi.val == 100) {
mood = "😍"
}
return mood;
}
}
})
</script>
最终样式: