手写react优惠券组件

张牙舞爪
• 阅读 4279

先看效果图

手写react优惠券组件

由于是截图,大小有些失真

实现分析

看到这个图,思考一下,就能明白,其实就两个难点:

  1. 左边的锯齿状是如何实现
  2. 中间的凹陷是如何实现

上述两个难点解决了,相信有css基础的都能写出这个组件。

实现锯齿效果

方法一:伪元素before和after

.sawtooth {
  /* 相对定位,方便让before和after伪元素绝对定位偏移 */
  position: relative;
  background:#e24141;
  width:400px;
  height:170px;
}

.sawtooth:before, .sawtooth:after {
    content: ' ';
    width: 0;
    height: 100%;
    /* 绝对定位进行偏移 */
    position: absolute;
    top: 0;
}

.sawtooth:before {
    /* 圆点型的border */
    border-right: 10px dotted white;
    /* 偏移一个半径,让圆点的一半覆盖div */
    left: -5px;
}

.sawtooth:after {
    /* 圆点型的border */
    border-left: 10px dotted white;
    /* 偏移一个半径,让圆点的一半覆盖div */
    right: -5px;
}


<div class="sawtooth"></div>

效果如下:
手写react优惠券组件

讲解

这个就是在开头和最后画了一个点状边框,然后平移边框,让边框的一部分覆盖原来的边框,利用圆点的颜色和背景色一样的特点,制作锯齿效果。如果不平移边框效果如下:

.sawtooth:before {
    /* 圆点型的border */
    border-right: 10px dotted white;
    /* 偏移一个半径,让圆点的一半覆盖div */
    left:0;
}

.sawtooth:after {
    /* 圆点型的border */
    border-left: 10px dotted white;
    /* 偏移一个半径,让圆点的一半覆盖div */
    right: 0px;
}

手写react优惠券组件

看了上图实现原理是不是一目了然了。但这也有一些缺点:
1.锯齿的颜色必须和背景色一样
2.无法画锯齿朝里的方式

方法二radial-gradient设置背景

radial-gradient讲解

用径向渐变创建图像。
简单语法:radial-gradient(circle, red 10px, blue 20px, yellow 30px);
形状是圆(也可以是椭圆),开始位置的颜色是red,中间颜色是blue,最后颜色是黄色。
10px表示从圆心开始10px范围内都是红色;
20px表示距离圆心20px的位置为blue,然后向两边扩散,直到里面10px的红色区域,和向外30px地方的yellow区域;
30px表示从30px开始往外都是yellow。
.div{
  margin:20px;
  height:100px;
  width:100px;
  background-image:radial-gradient(circle,red 10px,blue 20px,yellow 30px)
}

使用radial-gradient画圆点背景

  • 圆心设置成透明
  • 把过度颜色都设置成锯齿的颜色
  • 通过背景尺寸属性设置背景图的颜色,然后repeate
.div{
  margin:20px;
  height:106px;
  width:140px;
  background-image: radial-gradient(circle at center, transparent 6px,#28ACFF 7px);
  background-size: 20px 15px;
}

手写react优惠券组件

这样一个带圆点背景的div就出来了。然后通过设置宽度,只显示半个圆,左边的锯齿就出来了。width设置成10px如下效果

手写react优惠券组件

上边凹槽的实现

这个实现就比较简单了,通过绝对定位,用一个圆形元素覆盖父元素的边框。

问题:子元素无法覆盖父元素

在实现时遇到一个问题,就是子元素移动过去了,但是无法覆盖父元素的边框。这时,需要在组件外再套一层div,这个div设置成相对定位,然后把圆div设置成相对定义,再移动位置就能覆盖里面的组件div了。

开发优惠卷

通过上述的讲解,需要实现优惠卷所需要的知识点就都讲完了,下面让我们来实现开始效果的优惠卷吧。

结构分析

  1. 一个div顶级容器,设置成相对定位。(解决无法覆盖问题)
  2. 一个div组件容器,放到上面的div中
  3. 锯齿div(放到2中的的div)
  4. 粗体显示折扣的div(放到2中的的div)
  5. 虚线div(放到2中的的div)
  6. 折扣详情div(放到2中的的div)
  7. 两个圆形div,放到1或2中div都可以。

code


.parentContainer {
    position:relative;
    margin:20px;
    overflow:hidden;
}
.container {
    display:flex;
    border:1px solid #ddd;
    border-radius:3px;
    width:300px;
    height:105px;
    border-left:0;
}
.left {
    width:10px;
    height:106px;
    left:-1px;
    border:0px solid #ddd;
    border-radius:3px;
    background-image:radial-gradient(circle at center,transparent 6px,#28ACFF 4px);
    background-size:20px 15px;
    z-index:1
}
.couponName {
    text-align:center;
    border:0px solid red;
    line-height:106px;
    font-size:40px;
    font-family:PingFangSC-Medium;
    font-weight:500;
    color:rgba(40,172,255,1);
    margin-left:20px;
    margin-right:16px;
}
.subName {
    font-size:20px;
}
.topSemicircle {
    width:20px;
    height:20px;
    border:1px solid #ddd;
    border-radius:10px;
    position:absolute;
    left:80px;
    top:-16px;
    padding:0;
    background-color:#fff;
}
.bottomSemicircle {
    width:20px;
    height:20px;
    border:1px solid #ddd;
    border-radius:10px;
    position:absolute;
    left:80px;
    bottom:-16px;
    padding:0;
    background-color:#fff;
}
.dashed {
    border:1px dashed #ddd;
    margin-top:11px;
    margin-bottom:11px;
}
.right {
    display:flex;
    flex-direction:column;
    justify-content:center;
    align-items:flex-start;
    padding-left:10px;
}
.desc {
    font-size:10px;
    font-family:PingFangSC-Regular;
    font-weight:400;
    color:rgba(170,170,170,1);
    margin-top:10px;
}



<div class="parentContainer">
  <div class="container">
    <div class="left"></div>
    <div class="couponName">8<span class="subName">折</span></div>
    <div class="dashed"></div>
    <div class="right">
      <div>折扣卷7.5折</div>
      <div class="desc">400张</div>
      <div class="desc">有效时间:2018.09.21-2018.10.21</div></div>
    <div class="topSemicircle"></div>
    <div class="bottomSemicircle"></div>
  </div>
</div>

可以把代码赋值到下面的在线工具中看下效果
https://c.runoob.com/front-en...

React Code

根据自己需要再写成react版本,就易如反掌了。
//less 
.parentContainer {
  position: relative;
  margin: 20px;
  overflow: hidden;
}

.container {
  display: flex;
  border: 1px solid #ddd;
  border-radius: 3px;
  width: 312px;
  height: 105px;
  border-left: 0;
}

.left {
  width: 10px;
  height: 106px;
  left: -1px;
  border: 0px solid #ddd;
  border-radius: 3px;
  background-image: radial-gradient(
    circle at center,
    transparent 6px,
    #28acff 4px
  );
  background-size: 20px 15px;
  z-index: 1;
}

.leftInvalid {
  .left;
  background-image: radial-gradient(
    circle at center,
    transparent 6px,
    #aaaaaa 4px
  );
}

.couponName {
  text-align: center;
  border: 0px solid red;
  line-height: 106px;
  font-size: 40px;
  font-family: PingFangSC-Medium;
  font-weight: 500;
  color: rgba(40, 172, 255, 1);
  min-width: 62px;
  margin-left: 20px;
  margin-right: 16px;
}

.couponNameInvalid {
  .couponName;
  color: #aaaaaa;
}

.title {
  font-size: 16px;
  font-weight: 400;
  color: rgba(51, 51, 51, 1);
}

.invalidTitle {
  .title;
  color: rgba(170, 170, 170, 1);
}

.subName {
  font-size: 20px;
}

.semicircle {
  width: 20px;
  height: 20px;
  border: 1px solid #ddd;
  border-radius: 10px;
  position: absolute;
  left: 98px;
  padding: 0;
  background-color: #fff;
}

.topSemicircle {
  .semicircle;
  top: -16px;
}

.bottomSemicircle {
  .semicircle;
  bottom: -16px;
}

.dashed {
  border: 1px dashed #ddd;
  margin-top: 11px;
  margin-bottom: 11px;
}

.right {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding-left: 10px;
}

.desc {
  font-size: 10px;
  font-family: PingFangSC-Regular;
  font-weight: 400;
  color: rgba(170, 170, 170, 1);
  margin-top: 10px;
}

//组件代码
import React, { PureComponent } from 'react'
import styles from './index.less'

export default class CouponCard extends PureComponent {
  render() {
    const {
      valid = true,
      data = {
        id: 2323,
        couponDescription: '折扣卷8.5折',
        validDate: '2018.08.22-2018.09.12',
        number: 23,
        amount: 8.5,
        unit: '折',
      },
    } = this.props
    const amounts = data.amount.toString().split('.')
    return (
      <div className={styles.parentContainer}>
        <div className={styles.container}>
          <div className={valid ? styles.left : styles.leftInvalid} />
          <div className={valid ? styles.couponName : styles.couponNameInvalid}>
            {amounts[0]}
            <span className={styles.subName}>
              {amounts[1] ? `.${amounts[1]}` : ''}
              {data.unit}
            </span>
          </div>
          <div className={styles.dashed} />
          <div className={styles.right}>
            <div className={valid ? styles.title : styles.invalidTitle}>
              折扣卷{data.amount}
              {data.unit}
            </div>
            <div className={styles.desc}>{data.number}张</div>
            <div className={styles.desc}>有效时间:{data.validDate}</div>
          </div>
          <div className={styles.topSemicircle} />
          <div className={styles.bottomSemicircle} />
        </div>
      </div>
    )
  }
}



参考链接

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
4年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这