VUE实现box-shadow生成器

该文章描述了一个使用Vue.js构建的交互式工具,允许用户通过滑块调整box-shadow属性的各个值,包括水平阴影、垂直阴影、模糊半径、扩展半径、边框半径和颜色。此外,还有内阴影切换和颜色选择器。用户可以实时预览效果,并将生成的CSS样式代码复制到剪贴板。代码中实现了从hex颜色转换为rgba的功能,并监听各个输入变化以即时更新样式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最终效果:

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SamRol

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值