先看效果图

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

实现分析

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

  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>

效果如下:

讲解

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

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

看了上图实现原理是不是一目了然了。但这也有一些缺点:
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;
}

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

上边凹槽的实现

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

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

在实现时遇到一个问题,就是子元素移动过去了,但是无法覆盖父元素的边框。这时,需要在组件外再套一层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.propsconst 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>)}
}

参考链接

手写react优惠券组件相关推荐

  1. react 日期怎么格式化_手写React的Fiber架构,深入理解其原理

    熟悉React的朋友都知道,React支持jsx语法,我们可以直接将HTML代码写到JS中间,然后渲染到页面上,我们写的HTML如果有更新的话,React还有虚拟DOM的对比,只更新变化的部分,而不重 ...

  2. onclick 源码_精读:手写React框架 解析Hooks源码

    写在开头: 去年发表过一篇手写React,带diff算法,异步setState队列的文章,有一位阿里的朋友在下面评论,让我可以用hooks实现一次,也很简单,我当时觉得,这人有病,现在回过头来看,还是 ...

  3. 手写 React 第 2 节 - 初探 React 实现机制

    手写 React 第 2 节 - 初探 React 实现机制 前言 1. jsx 语法 2. createElement 实现 3. ReactDOM.render 实现 前言 在上一节[手写 Rea ...

  4. 手写 React 第 4 节 - 实现 Fiber

    手写 React 第 4 节 - 实现 Fiber 前言 1. Fiber 的作用 2. Fiber 数据结构 3. 实现 Fiber 前言 在上一节[手写 React 第 3 节 - 实现函数组件/ ...

  5. Vue手写一个日历组件

    工作中遇到一个需求是根据日历查看某一天/某一周/某一月的睡眠报告,但是找了好多日历组件都不是很符合需求,只好自己手写一个日历组件,顺便记录一下. 先来看看设计图是什么样式, 跟其他日历有点不一样,这个 ...

  6. vue 多点触控手势_手写 Vue 手势组件__Vue.js

    前言 最近需要使用手指捏合扩大的手势操作,找了几个组件,要么对 Vue 适配不好,要么量级太大,决定自己手写手势操作. 项目与效果预览 思路 直接在 DOM 上绑定 touchstart .touch ...

  7. Android 自定义View 手写瀑布流组件FlowLayout

    目录 FlowLayout实现关键步骤: 1.创建一个view继承自ViewGroup 2.重写并实现onMeasure方法 3.重写并实现onLayout方法 纸上得来终觉浅,绝知此事要躬行. 动手 ...

  8. 【React】手写虚拟滚动组件(二)可自动获取不定高度的虚拟滚动组件

    前言 上次那篇写的虚拟滚动后来使用发现在某些情况并不是特别好用,并且只支持固定高度.我看了下umihook的虚拟滚动,发现也不是很好用,它支持手动设定每个元素高度,但也不能支持不定高度,而且限定更多了 ...

  9. html中collapse代码怎么写,面试题: 手写collapse(折叠组件)的css/html部分

    做一个组件库不难 其实vue/react等框架的出现, 让自己做一个ui变得简单, 大部分的js逻辑都被库封装, 反而组件的代码主要都是css, 所以只要css写好了, 一个组件就完成60%以上了. ...

最新文章

  1. GitHub 热榜:来膜拜这个流弊的 AI 框架!
  2. 多线程测试工具groboutils的使用
  3. xgboost使用自定义的loss function
  4. Silverlight 2 应用程序部署到任意HTML页面
  5. 对人工智能神经网络的认识
  6. Spark API编程动手实战-08-基于IDEA使用Spark API开发Spark程序-01
  7. 【BZOJ1044】【tyvj3511】【codevs1870】木棍分割,二分答案+滚动数组+前缀和DP
  8. 敲了 10000 小时代码,我也没能成为一名高级程序员
  9. PHP入门part1
  10. Numpy的使用方法
  11. php all函数,PHP 函数 preg_match_all()
  12. Windows核心编程_锁屏
  13. python攻击校园网_Python--校园网爬虫记
  14. c盘找不到appdata
  15. Matebook xpro2019指纹驱动不可用
  16. 论文阅读:MobileNetV2: Inverted Residuals and Linear Bottlenecks(MobileNetV2)
  17. 2019XUPT_ACM校赛总结
  18. 【官方教程】使用Quick-Cocos2d-x搭建一个横版过关游戏(六)
  19. css动画其他div,删除另一个div时的CSS3 Transition动画
  20. 红米3 android驱动,红米3驱动最新版

热门文章

  1. PPT文件打开的时候需要输入密码才能编辑?
  2. Python 数据采集-爬取学校官网新闻标题与链接(进阶)
  3. android 酷狗demo_Android仿酷狗皮肤预览界面的实现(利用canvas缩放的原理)
  4. 【JY】SAFE考虑徐变和收缩效应的长期挠度分析
  5. 算法编程11:二分法求平方根
  6. 我的世界服务器欢迎语怎么修改,使用命令方块实现服务器欢迎语
  7. centos 网卡重启方法
  8. 在Excel中使用FREQUENCY函数统计各分数段人数
  9. 怎么清洁计算机主机内部,怎么清理电脑灰尘 怎样清理电脑主机内的灰尘
  10. HAProxy快速入门(一)——简介及原理