最终效果:
Html结构
一层结构
<div class="body">
<div class="container">
<div class="result"></div>
<div class="setting"></div>
<div class="code-container"></div>
</div>
</div>
二层结构
<div class="preview" :style="{'box-shadow':`${isInset ? 'inset':' ' } ${xshadow}px ${yshadow}px ${blur}px ${spread}px ${fin_color}`,'border-radius':border + 'px'}"></div>
<div class="range-wrapper">
<label for="x-shadow">Horizontal Shadow :</label>
<input type="range" id="x-shadow" min="-100" max="100" v-model=xshadow>
</div>
<div class="range-wrapper">
<label for="y-shadow">Vertical Shadow :</label>
<input type="range" id="y-shadow" min="-100" max="100" v-model=yshadow>
</div>
<div class="range-wrapper">
<label for="blur-r">Blur Radius :</label>
<input type="range" id="blur-r" min="0" max="100" v-model=blur>
</div>
<div class="range-wrapper">
<label for="spread-r">Spread Radius :</label>
<input type="range" id="spread-r" min="0" max="100" v-model=spread>
</div>
<div class="range-wrapper">
<label for="border-r">Border Radius :</label>
<input type="range" id="border-r" min="0" max="100" step="0.1" v-model=border>
</div>
<div class="range-wrapper">
<label for="shadow-opacity">Shadow Opacity :</label>
<input type="range" id="shadow-opacity" min="0" max="1" step="0.01" v-model=opacity>
</div>
<div class="input-wrapper">
<label for="inset-shadow">Inset Shadow :</label>
<input type="checkbox" id="inset-shadow" v-model="isInset">
</div>
<div class="color-wrapper">
<label for="color-shadow">Color Shadow :</label>
<input type="color" id="color-shadow" v-model="color">
</div>
<textarea id="styles" rows="2">{{style}}</textarea>
<button id="copy-style" @click="copyStyle">{{btn_text}}</button>
功能实现
1.修改box的样式
为input标签绑定v-modle,来实现双向绑定。
<input type="range" id="x-shadow" min="-100" max="100" v-model=xshadow>
<input type="range" id="y-shadow" min="-100" max="100" v-model=yshadow>
<input type="range" id="blur-r" min="0" max="100" v-model=blur>
<input type="range" id="spread-r" min="0" max="100" v-model=spread>
<input type="range" id="border-r" min="0" max="100" step="0.1" v-model=border>
<input type="range" id="shadow-opacity" min="0" max="1" step="0.01" v-model=opacity>
<input type="checkbox" id="inset-shadow" v-model="isInset">
<input type="color" id="color-shadow" v-model="color">
为box绑定内联样式
<div class="preview" :style="{'box-shadow':`${isInset ? 'inset':' ' } ${xshadow}px ${yshadow}px ${blur}px ${spread}px ${fin_color}`,'border-radius':border + 'px'}"></div>
我们知道input的color只有rgb而没有rgba,所以我们需要写一个函数来生成rgba。
HexToRGBA(color,opacity){
const r = parseInt(color.substr(1,2),16);
const g = parseInt(color.substr(3,2),16);
const b = parseInt(color.substr(5,2),16);
this.fin_color = `rgba(${r},${g},${b},${opacity})`
},
2.更新文本区的代码
UpdataStyle(){
//<textarea id="styles" rows="2">{{style}}</textarea>
this.style = `box-shadow:${this.isInset ? 'inset':' ' } ${this.xshadow}px ${this.yshadow}px ${this.blur}px ${this.spread}px ${this.fin_color};\nborder-radius:${this.border};`
},
3.复制文本
copyStyle(){
var area = document.querySelector("#styles");
area.select();
document.execCommand('copy');
this.btn_text = "Copy!"
setTimeout(()=>{
this.btn_text = "Copy Styles"},3000)
}
完整代码
<template>
<div class="body">
<div class="container">
<div class="result">
<div class="preview" :style="{'box-shadow':`${isInset ? 'inset':' ' } ${xshadow}px ${yshadow}px ${blur}px ${spread}px ${fin_color}`,'border-radius':border + 'px'}"></div>
</div>
<div class="setting">
<div class="range-wrapper">
<label for="x-shadow">Horizontal Shadow :</label>
<input type="range" id="x-shadow" min="-100" max="100" v-model=xshadow>
</div>
<div class="range-wrapper">
<label for="y-shadow">Vertical Shadow :</label>
<input type="range" id="y-shadow" min="-100" max="100" v-model=yshadow>
</div>
<div class="range-wrapper">
<label for="blur-r">Blur Radius :</label>
<input type="range" id="blur-r" min="0" max="100" v-model=blur>
</div>
<div class="range-wrapper">
<label for="spread-r">Spread Radius :</label>
<input type="range" id="spread-r" min="0" max="100" v-model=spread>
</div>
<div class="range-wrapper">
<label for="border-r">Border Radius :</label>
<input type="range" id="border-r" min="0" max="100" step="0.1" v-model=border>
</div>
<div class="range-wrapper">
<label for="shadow-opacity">Shadow Opacity :</label>
<input type="range" id="shadow-opacity" min="0" max="1" step="0.01" v-model=opacity>
</div>
<div class="input-wrapper">
<label for="inset-shadow">Inset Shadow :</label>
<input type="checkbox" id="inset-shadow" v-model="isInset">
</div>
<div class="color-wrapper">
<label for="color-shadow">Color Shadow :</label>
<input type="color" id="color-shadow" v-model="color">
</div>
</div>
<div class="code-container">
<textarea id="styles" rows="2">{{style}}</textarea>
<button id="copy-style" @click="copyStyle">{{btn_text}}</button>
</div>
</div>
</div>
</template>
<script>
export default{
data(){
return{
xshadow:-6,
yshadow:15,
blur:30,
spread:30,
border:70,
opacity:0.5,
isInset:false,
color:"#000000",
fin_color:"",
style:"",
btn_text:"Copy Styles"
}
},
mounted(){
this.HexToRGBA(this.color,this.opacity);
this.UpdataStyle();
},
methods:{
// 生成RGBA
HexToRGBA(color,opacity){
const r = parseInt(color.substr(1,2),16);
const g = parseInt(color.substr(3,2),16);
const b = parseInt(color.substr(5,2),16);
this.fin_color = `rgba(${r},${g},${b},${opacity})`
},
//更新样式描述
UpdataStyle(){
this.style = `box-shadow:${this.isInset ? 'inset':' ' } ${this.xshadow}px ${this.yshadow}px ${this.blur}px ${this.spread}px ${this.fin_color};\nborder-radius:${this.border};`
},
//复制样式
copyStyle(){
var area = document.querySelector("#styles");
area.select();
document.execCommand('copy');
this.btn_text = "Copy!"
setTimeout(()=>{
this.btn_text = "Copy Styles"
},3000)
}
},
watch:{
"opacity":function(){
this.UpdataStyle();
this.HexToRGBA(this.color,this.opacity);
},
"color":function(){
this.HexToRGBA(this.color,this.opacity);
},
"xshadow":function(){
this.UpdataStyle();
},
"yshadow":function(){
this.UpdataStyle();
},
"blur":function(){
this.UpdataStyle();
},
"spread":function(){
this.UpdataStyle();
},
"isInset":function(){
this.UpdataStyle();
},
}
}
</script>
<style lang="less" scope>
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@500&display=swap');
.body{
height: 100vh;
font-family: 'Roboto Mono', monospace;
background-color: #311b92;
}
label{
font-size: 15px;
user-select: none;
}
.container{
top: 50%;
left: 50%;
width: 80vmin;
padding: 30px;
position: absolute;
background-color: #fff;
transform: translate(-50%,-50%);
border-radius: 25px;
box-shadow: 0 20px 40px rgba(2, 42, 83, 0.2);
}
.result{
padding: 20px 0 120px;
.preview{
position: relative;
width: 200px;
height: 200px;
margin: auto;
border-radius: 70px;
background-color: #311b92;
box-shadow: -6px 15px 30px 6px rgba(0, 0, 0, 0.5);
user-select: none;
}
}
.setting{
display: grid;
grid-template-columns: 6fr 6fr;
gap: 15px 25px;
}
.range-wrapper, .color-wrapper{
display: flex;
flex-direction: column;
justify-content: space-between;
user-select: none;
}
input[type="range"]{
width: 100%;
cursor: pointer;
}
input[type="checkbox"]{
cursor: pointer;
}
.code-container{
margin-top: 20px;
display: grid;
grid-template-columns: 6fr 2fr;
gap: 10px
}
.code-container button{
background-color: #311b92;
border-radius: 5px;
cursor: pointer;
border:none;
color: #fff;
user-select: none;
}
textarea{
resize: none;
padding: 5px;
border: 1px solid #000;
}
.color-wrapper,.input-wrapper{
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: 5px;
user-select: none;
}
input[type="color"]{
width: 25px;
height: 25px;
border: 1px solid #ccc;
}
</style>