深度优先

这个家伙好懒,除了文章什么都没留下

0%

1
2
3
4
作者:codercao
链接:https://juejin.im/post/5b6d0c5cf265da0f504a837f
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

伪类经常与伪元素混淆,伪元素的效果类似于通过添加一个实际的元素才能达到,而伪类的效果类似于通过添加一个实际的类来达到。实际上css3为了区分两者,已经明确规定了伪类用一个冒号来表示,而伪元素则用两个冒号来表示。伪类与伪元素的本质区别就是是否抽象创造了新元素。具体的伪类和伪元素相关知识本文就不深入,下面介绍一下从青铜到王者10个css3伪类使用技巧和运用。直击案例代码

青铜-1、伪类实现盒子阴影

众所周知,Animate/transition box-shadow 可以使用box-shadow属性来实现盒子阴影效果,但repaint消耗较多,于是这里提出通过修改伪元素的透明度来实现盒子阴影

实现原理:

通过改变透明度,这样从一个非默认值更新它的值,就不需要承担任何重绘(参见:https://csstriggers.com/opacity)

(ps:貌似莫名的解锁了一个关于前端css优化,坏笑坏笑)

这里设置一个空的伪元素设置阴影透明度为0隐藏,再通过鼠标悬停恢复它的透明度,下面是传统和伪类实现的代码对比

1
2
3
4
5
6
7
8
9
10
<div class="before">
<h1>Before</h1>
<p>Animate/transition box-shadow 可以使用box-shadow属性来实现盒子阴影效果,但重绘消耗较多</p>
</div>
<hr />
<div class="after">
<h1>After</h1>
<p>通过修改伪元素的透明度来实现同样的效果,没有重绘消耗</p>
</div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 .before {
padding: 1em;
background-color: #fff;
-webkit-transition: 0.2s;
transition: 0.2s;
}
.before:hover {
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
}
.after {
position: relative;
padding: 1em;
background-color: #fff;
}
.after:before {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
opacity: 0;
will-change: opacity;
-webkit-transition: 0.2s;
transition: 0.2s;
}
.after:hover:before {
opacity: 1;
}
复制代码

效果:(完整代码见后文链接)

青铜-2、伪元素:before实现的面包屑导航栏

1
2
3
4
5
6
7
8
9
10
<ul class="breadcrumb">
<li><a href="#">Home</a>
</li>
<li><a href="#">Pictures</a>
</li>
<li><a href="#">Summer 15</a>
</li>
<li>Italy</li>
</ul>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ul.breadcrumb {
padding: 8px 16px;
list-style: none;
background-color: #eee;
}
ul.breadcrumb li {
display: inline;
}
ul.breadcrumb li+li:before {
padding: 8px;
color: black;
content: "/\00a0";
}
ul.breadcrumb li a {
color: green;
}
复制代码

效果:

青铜-3、伪元素实现悬停时按钮填充和边界浮动动画

效果:(完整代码见后文链接)

青铜-4、伪类after实现的三角箭头

实现原理:三边设置边框,箭头指向的那个方向的border不用设置,位于箭头两边的边框颜色为透明(transparent),对边为主体边框颜色(较大的)/主体背景颜色(较小的),因为我们要有边框颜色的三角箭头,当第一个箭头(较大的)被第二个箭头(较小的)通过准确覆盖之后剩下没被覆盖的边缘就是合成三角箭头的边框了,其颜色就是较大的那个三角箭头的颜色,可调。而较小的那个三角箭头的颜色要设置成主体颜色,进行负值定位偏移时要把主体边框盖住,从而与主体合在一起了

1
2
3
4
5
6
7
8
9
<div class='container'>
<img alt='' src='http://placehold.it/400x200'>
<div class='arrow-left'></div>
</div>
<div class='container new'>
<div class='arrow-right'></div>
<img alt='' src='http://placehold.it/400x200'>
</div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.arrow-left:before {
z-index: 9999;
content: "";
display: block;
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-right: 20px solid #E9E9E9;
position: absolute;
left: -20px;
top: 80px;
}

复制代码

效果:(完整代码见后文链接)

青铜-5、伪类after实现的图片箭头

效果:(完整代码见后文链接)

青铜-6、伪元素实现带角度的底部边界(倾斜的边界)

原理:修改webkit-transform: skewY属性来修改倾斜度(旋转也是一样的道理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.edge--bottom {
position: relative;
z-index: 1;
}
.edge--bottom:after {
background: inherit;
content: '';
display: block;
height: 50%;
left: 0;
position: absolute;
right: 0;
z-index: -1;
}
.edge--bottom:after {
bottom: 0;
-webkit-transform: skewY(-1.5deg);
-ms-transform: skewY(-1.5deg);
transform: skewY(-1.5deg);
-webkit-transform-origin: 100%;
-ms-transform-origin: 100%;
transform-origin: 100%;
}
复制代码

效果:(完整代码见本文结尾链接)

王者-1、伪元素和平移(translate)变换实现的提示框

1
2
3
4
5
6
7
<div class="row">
<a rel="nofollow" rel="noreferrer" href="#" class="btn tooltip top">
<span>TOOLTIP TOP</span>
<span class="tooltip-content">Lorem ipsum dolor sit amet</span>
</a>
</div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.tooltip .tooltip-content::after {
background: #05a8ff;
content: "";
height: 10px;
position: absolute;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
width: 10px;
}
.tooltip.top .tooltip-content {
bottom: calc(100% + 1.5em);
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.tooltip.top .tooltip-content::after {
bottom: -5px;
left: 50%;
margin-left: -5px;
}
复制代码

效果:(完整代码见本文结尾链接)

王者-2、使用CSS3伪元素实现的自动打字动画

原理:Typing Animation with Pseudo-Elements 看起来是打字,其实是使用伪元素覆盖在字符串上,然后逐渐减少伪元素覆盖宽度来实现的视觉效果

1
2
3
4
5
6
7
<div>
<h1>Typing Animation</h1>
<p class="tagline">
<span class="tagline-skill"><span class="tagline-skill_inner">webdesign</span></span>
</p>
</div>
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
.tagline-skill_inner:after {
content: "";
position: absolute;
top: -1px;
right: 0;
bottom: -2px;
left: 0;
border-left: 1px solid #fff;
background-color: #2a2a28;
-webkit-animation: animatetoright 1s steps(10) infinite alternate;
animation: animatetoright 1s steps(10) infinite alternate;
}
复制代码

效果:(完整代码见本文结尾链接)

王者-3、CSS3 伪元素构建的文章水印背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
h1 {
position: relative;
margin: 0;
font-weight: bold;
letter-spacing: -0.05rem;
line-height: 1;
text-transform: uppercase;
z-index: 10;
}
h1:before {
content: "2018/08";
font-family: monospace;
font-size: 10rem;
position: absolute;
top: 2rem;
left: -2rem;
z-index: 0;
line-height: 1;
color: rgba(50, 25, 0, 0.1);
}
复制代码

效果:(完整代码见本文结尾链接)

王者-4、CSS3 用伪元素做页码摘要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
a {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: row nowrap;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-box-align: baseline;
-webkit-align-items: baseline;
-ms-flex-align: baseline;
align-items: baseline;
text-decoration: none;
-webkit-transition: color .2s ease-in-out;
transition: color .2s ease-in-out;
}
a::before {
height: .1em;
-webkit-box-flex: 1;
-webkit-flex: 1 1 auto;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
-webkit-box-ordinal-group: 2;
-webkit-order: 1;
-ms-flex-order: 1;
order: 1;
background: left bottom/contain repeat-x url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDIiPjxjaXJjbGUgZmlsbD0iI2ZmZiIgY3g9IjMuNSIgY3k9IjEiIHI9IjEiLz48L3N2Zz4=);
content: '';
}
a::after {
-webkit-box-ordinal-group: 3;
-webkit-order: 2;
-ms-flex-order: 2;
order: 2;
content: "p." attr(data-page);
}
复制代码

效果:(完整代码见本文结尾链接)

王者-5、伪类兼容性了解一下

1、IE8不支持CSS3中很多特性,比如伪元素nth-child,可以使用+号(代表相邻元素)来实现相同功能

2、Google的IE9.js是解决IE5.5到IE8 CSS3特性兼容性问题的JS库

最后

CSS的世界很美好,每个知识点都可以值得深入研究和实践,对于伪类、伪元素也有很多土味特效可以写出来,比如说图片遮罩、图片背景模糊,更多高级的鼠标经过事件特效等等,上边的10个案例是我个人工作上总结和参考踏得网上资源整理,希望对大家有所帮助

最后附上github示例源码,可下载体验。

小程序开发还是蛮简单的,之前倒腾过两个小程序,也都上线了。

今天开始第三个,自己写了一个日历模块,主要涉及日历的展现布局,标记日期,点击事件,左右滑动切换月份等。

效果图:

calendar.wxml 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<view class='main'>
<view class='calendar-con'>
<view class="calendar-top">
<view class="current-date">{{nowDate}}</view>
<picker mode="date" value="{{date}}" start="1995-01-01" end="2025-12-31" bindchange="bindDateChange">
<view class="calendar-history">选择日期</view>
</picker>
</view>
<view class="calendar-main">
<swiper autoplay="{{autoplay}}" circular="true" bindanimationfinish="bindanimationfinish" data-key="{{swipr-item}}">
<block wx:for="[0]" wx:key="key">
<swiper-item>
<view class="calendar-list">
<view wx:for="{{arr}}" wx:for-item="item" wx:key="key" class="calendar-item {{item.itmeClass}} {{maskId==item.day?'mask':''}}" bindtap="ClickDay" data-day="{{item.day}}" data-date="{{item.date}}">
{{item.day}}
</view>
</view>
</swiper-item>
</block>
</swiper>
</view>
</view>
<view class='calendar-bottom'>
<view class='calendar-bottom-title'>
<view class=''>雷阵雨 23 至 30°C</view>
<view class=''>天气</view>
</view>
<view class='calendar-bottom-body'>
<view class=''>这是一些内容,巴拉巴拉...</view>
<view class=''>点击了:{{clickDay}}</view>
</view>
</view>
</view>

calendar.wxss 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
page {
width: 100%;
/* height: 100%; */
background-color: #767ec9;
}

.main {
margin-top: 30rpx;
}

.calendar-con {
margin: 0 auto;
width: 682rpx;
height: 684rpx;
background: url('http://120.77.181.53/img/calendar_con.jpg');
background-size: cover;
padding: 10rpx;
border-radius: 20rpx;
}

.calendar-top {
display: flex;
justify-content: space-between;
margin: 5rpx 18rpx;
}

.current-date {
padding-top: 5rpx;
padding-left: 65rpx;
color: #b25d06;
font-size: 18px;
}

.calendar-history {
width: 135rpx;
height: 45rpx;
border-radius: 8rpx;
background-color: #b25d06;
color: #fff;
text-align: center;
font-size: 11px;
line-height: 45rpx;
margin-right: 18rpx;
}

.calendar-main {
width: 100%;
}

.calendar-list {
margin-top: 76rpx;
margin-left: 32rpx;
display: flex;
flex-wrap: wrap;
}

.calendar-item {
width: 85rpx;
height: 85rpx;
margin: 1rpx;
background-color: #fffff2;
border-radius: 12rpx;
display: flex;
justify-content: center;
align-items: center;
color: #ad560e;
font-size: 20px;
font-weight: bold;
}

.styles-icon2 {
background-image: url(http://120.77.181.53/img/icon-2.png);
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
}

.styles-icon3 {
background-image: url(http://120.77.181.53/img/icon-7.png);
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
}

.styles-icon4 {
background-image: url(http://120.77.181.53/img/icon-6.png);
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
}

.calendar-bottom {
margin: 0 auto;
margin-top: 35rpx;
width: 682rpx;
height: 380rpx;
background: url('http://120.77.181.53/img/calendar_bottom.jpg');
background-size: cover;
padding: 10rpx;
border-radius: 20rpx;
}

.calendar-bottom-title {
display: flex;
justify-content: space-between;
width: 460rpx;
height: 55rpx;
line-height: 55rpx;
margin: 0 auto;
margin-top: 10rpx;
color: #ad560e;
font-size: 18px;
}

.calendar-bottom-body {
width: 460rpx;
margin: 30rpx;
color: #777;
}

.mask {
background: rgba(66, 66, 66, 0.2);
}

swiper{
height: 600rpx;
}

calendar.js 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// pages/calendar/calendar.js
Page({

/**
* 页面的初始数据
*/
data: {
arr: [],
nowDate: null,
nowDay: 1,
clickDay: null,
maskId: null,
autoplay: false,
current: 0,
},

/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
var date = new Date();
this.setData({
arr: this.GetCalendarData(date),
nowDate: this.GetNowTime(date),
nowDay: date.getDate()
})
},

//初始化日历数据
GetCalendarData(now) {
var data = [];
var timestamp = Date.parse(now.getFullYear() + "/" + (now.getMonth() + 1) + "/" + '1');
var date = new Date(timestamp);
var item = {
date: '',
day: '',
itmeClass: ''
};
for (var i = 1; i <= 42; i++) {
if (i <= this.GetWeekDay(now)) {
data.push(item);
} else if (now.getMonth() == date.getMonth()) {
data.push({
date: this.GetNowTime(date),
day: date.getDate(),
itmeClass: ''
});
date.setDate(date.getDate() + 1);
} else {
data.push(item);
}
}
//添加标记
var index = now.getDate() + this.GetWeekDay(now) - 1;
data[index] = {
day: data[index].day,
date: data[index].date,
itmeClass: 'styles-icon2'
};

data[26] = {
day: data[26].day,
date: data[index].date,
itmeClass: 'styles-icon3'
};

data[11] = {
day: data[11].day,
date: data[index].date,
itmeClass: 'styles-icon4'
};
return data;
},
//或某个月得一号周几
GetWeekDay: function(now) {
var date = Date.parse(now.getFullYear() + "/" + (now.getMonth() + 1) + "/" + '1');
var weekday = new Date(date);
return weekday.getDay();
},

//获取当前日期
GetNowTime: function(now) {
var year = now.getFullYear();
var month = now.getMonth() + 1;
var day = now.getDate();
month < 10 ? month = '0' + month : month;
day < 10 ? day = '0' + day : day;
var formatDate = year + '/' + month + '/' + day;
return formatDate;
},
//点击日期事件
ClickDay: function(event) {
var day = event.target.dataset.day;
var date = event.target.dataset.date;
if (day != '') {
this.setData({
clickDay: date,
maskId: day,
nowDate: date
})
}
},
//选择日期
bindDateChange: function(e) {
var date = new Date(e.detail.value);
this.setData({
arr: this.GetCalendarData(date),
clickDay: null,
maskId: null,
nowDate: this.GetNowTime(date),
})
},

bindanimationfinish: function(e) {
var that = this;
var date = new Date(that.data.nowDate);
var index = that.data.current - e.detail.current;
index = index == 2 ? -1 : index;
index = index == -2 ? 1 : index;
if (index != 0) {
date.setMonth(date.getMonth() - index);
that.setData({
current: e.detail.current,
arr: that.GetCalendarData(date),
clickDay: null,
maskId: null,
nowDate: that.GetNowTime(date),
})
}
},
})

不会写前端代码的,不是一个好的后端开发人员!

在本地调试可以正常发送邮件,在服务器上发送失败

原因25端口被阿里云禁用,不能被开启,只能尝试用465 端口采用加密方式发送邮件。

然而 使用 smtp.163.com 的用 465端口发送还是失败,用自己网站的邮箱发送也是失败的报554错误啥的

最后用QQ的邮箱成功了!

Demo:

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public class MailHelper
{
public static readonly string MailName = "邮件中心";
public static readonly string body = "XXXXX";

public static string send(string toMail, string MailServer, string MailUserName, string MailPassword, int Port, bool EnableSsl)
{
try
{
SmtpClient smtpClient = new SmtpClient();
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.EnableSsl = EnableSsl;
smtpClient.Host = MailServer;
smtpClient.Port = Port;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = (ICredentialsByHost)new NetworkCredential(MailUserName, MailPassword);
MailMessage message = new MailMessage()
{
Priority = MailPriority.Normal,
From = new MailAddress(MailUserName, "XXXX", Encoding.UTF8),
Subject = "主题",
SubjectEncoding = Encoding.UTF8,
To = {
toMail
}
};
message.SubjectEncoding = Encoding.GetEncoding(936);
message.IsBodyHtml = true;
message.BodyEncoding = Encoding.GetEncoding(936);
message.Body = "<font color='red'>" + MailHelper.body + "</font><br>";
smtpClient.Send(message);
return "邮件发送成功";
}
catch (Exception ex)
{
return ex.Message;
}
}


public static string send1(string toMail, string MailServer, string MailUserName, string MailPassword, int Port, bool EnableSsl)
{
System.Web.Mail.MailMessage mmsg = new System.Web.Mail.MailMessage();
//邮件主题
mmsg.Subject = "hello, world";
mmsg.BodyFormat = System.Web.Mail.MailFormat.Html;
//邮件正文
mmsg.Body = "hello, world。哈哈哈哈哈哈,听说会被屏蔽掉的";
//正文编码
mmsg.BodyEncoding = Encoding.UTF8;
//优先级
mmsg.Priority = System.Web.Mail.MailPriority.Normal;
//发件者邮箱地址
mmsg.From = MailUserName;
//收件人收箱地址
mmsg.To = toMail;

mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
//用户名
mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", MailUserName);
//密码
mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", MailPassword);
//端口
mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", Port);
//是否ssl
mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", EnableSsl);
//Smtp服务器
System.Web.Mail.SmtpMail.SmtpServer = MailServer;

try
{
System.Web.Mail.SmtpMail.Send(mmsg);
return "发送成功";
}
catch (Exception ex)
{
return "发送失败,失败原因:" + ex.Message;
}
}
}