一篇里面的函数比较好的实现方式是:
function getIntRandom(alt, penSize) {
return Math.floor(Math.random() * alt/penSize) * penSize;
}
先在一个范围内生成需要的数字,然后放大相应的倍数不就好了吗? 感谢大神,行家一出手,就知有没有,这是真真滴,在我用while去让计算机做重复计算的时候,动下脑子,用数学思维就可以轻松解决了呀。
继续实现那个画小正方形的东西吧,
1, 新建一个html,写入基础页面结构代码(为了等下方便解释,给前面手工加了行号,要复制使用的话,想办法把最前面的行号得取掉):
001 <!doctype html>
002 <html lang="zh">
003 <head>
004 <meta charset="UTF-8">
005 <title>像素风头像生成器</title>
006 </head>
007 <body>
008 <div id="wrapper">
009 <canvas id="myCanvas" width="200" height="200" style="border:1px solid #d3d3d3;">
010 Your browser does not support the HTML5 canvas tag.
011 </canvas>
012 <p>
013 <a href="javascript:;" id="mkephoto" onclick="makePhoto();">生成</a>
014 </p>
015 </div>
016
017
018 <style type="text/css" media="screen">
019 html {
020 margin: 0;
021 padding: 0;
022 font: 62.5%/1 Georgia, "Microsoft Yahei", sans-serif;
023 }
024 body {
025 font: 1.2/1.5;
026 }
027
028 #wrapper {
029 margin: 5em auto;
030 text-align: center;
031 }
032
033 .ctlArea{
034 text-align: center;
035 border: 1px dashed #c0c0c0;
036 border-radius: 4px;
037 }
038
039 </style>
040 </body>
041 </html>
效果是这样子的
在第13行,给`<a>`标签加了`onclick`点击事件,直接调用`makePhoto`这个函数,接下来咱就去实现这个函数。
去行号的话,用正则表达式来可以:将`^\d\d\d `替换成没有就好了,再可以在列模式里面直接删除,放一张图吧,今天内容少,觉得编辑器好用的,去搜EverEdit,也可以给我私信,个人觉得在windows里面比sublime好使,关键对于编码这块支持很好(不是免费的)。
正则表达式是一个好东西,强烈建议客官有时间去学习
2, 在`</body>`前面直接写javascript部分:
039 </style>
040
041 <script type="text/javascript">
042
043
044 function makePhoto () {
045
046 var backColor = "transparent";
047 var imgWidth = 200;
048 var penSize = 40;
049 var penColor = "rgb("+getRemodInt(255)+","+getRemodInt(255)+","+getRemodInt(255)+")";
050 var c = document.getElementById("myCanvas");
051
052 c.width = imgWidth;
053 c.height = imgWidth;
054
055 var ctx=c.getContext("2d");
056 ctx.fillStyle="green";
057 //ctx.fillRect(40,0,10,10);
058
059 // x从cab 0-50 取 值,再拿这个值取到对称数,
060 // y 从0 到 100 做10 次增加
061
062 ctx.fillStyle = backColor;
063 //console.log(backColor);
064 ctx.fillRect(0, 0, imgWidth, imgWidth);
065 ctx.fillStyle = penColor;
066 for (var yl = 0; yl <= c.height; yl += penSize) {
067 (function(rmd){
068 console.log(rmd);
069 for (var i = 0; i < rmd; i++) {
070 var x1 = getRemodIntByPenSize(imgWidth , penSize);
071 ctx.fillRect(x1, yl, penSize, penSize);
072 //ctx.fillRect(x2, yl, penSize, penSize);
073 }
074 })(getRemodInt(imgWidth / penSize));
075 }
076
077 }
078
079 //返回一个在(0,Alt]区间的能被penSize整除的数
080 //确定具体亮哪几个像素
081 function getRemodIntByPenSize (alt, penSize) {
082 return Math.floor(Math.random() * alt / penSize) * penSize;
083 }
084 //返回指定范围以内的整数 传入3返回 132
085 //确定一行亮几个像素
086 function getRemodInt(alt) {
087 return Math.floor(Math.random() * alt) + 1;
088 }
089
090 makePhoto();
091 </script>
092 </body>
解释一下,
第44~77行是makePhoto函数,
46~49行定义了画布大小,背景颜色,像素大小,画笔颜色这些东西。
50行拿到了`canvas`,也就是画布,后面两行定义了画布的长宽。
62~64行把画布整个用背景色涂了一遍。
66~75行,用一个for循环确定要画的像素点的y坐标,就是一行一行地往下移动。
79~83行,84~88行的两个函数,一个负责确定这一行里面画出来几个像素,一个负责确定要画的这几个像素的x坐标放在哪。
67~74行,是一个闭包,确保每次循环过来的时候,内部执行的东西是一个独立的,不受上一次循环时候留下的一些变量影响。
69~73行,一个小循环,就是画一行的像素点,画几个由`rmd`这个值决定,`rmd`是要传入这个闭包函数的值,在74行调用的时候用`getRemodInt(imgWidth / penSize)`给算出来传了进去。(这里如果不懂的话,没关系,只要知道这个东西是个闭包,有兴趣的话,可以去搜索学习一下)
就这些了,先设法看到效果再说,不要怕里面不懂的地方。(高能预警)个人觉得哈,学编程就得拿来先用,先试试再说,然后再给解剖了,看看具体是怎么个实现的,用到了哪些知识点,再一个个小知识点地去把它给理解,化为已用,所以,不要觉得有一个地方不懂或者做不出来的时候,就放手,及时搜索,及时求助,及时尝试。和小孩子学说话一样,刚开始总会跑音,太正常了,学习本身就是一点点积累的过程。
就这样。效果图再来一张,不然没法放封面呀。
神奇的封面
在现代网页设计中,个人主页是一个展示个人信息、技能、事件等的重要载体。为了吸引访客的注意力并提供良好的用户体验,设计师通常会运用各种技巧和效果来增加页面的吸引力。本文将介绍如何使用CSS创建一个惊叹的个人主页介绍卡片,展示独特魅力;
首先,需要定义基本的HTML结构来容纳个人主页介绍卡片;
这里外层使用一个div包裹,里面使用三个<div>元素作为包裹容器布局,并在其中添加所需的图像、内容和按钮等:
<div class="card">
<div class="box">
<div class="img_box">
<video
src="./assets/video.mp4"
muted
autoplay
loop
/>
</div>
</div>
<div class="box">
<div class="content">
<h2>
Alexa
<br>
<span>
Professional Artist
</span>
</h2>
<ul>
<li>
Posts
<span>22</span>
</li>
<li>
Followers
<span>999+</span>
</li>
<li>
Following
<span>7</span>
</li>
</ul>
<button>Follow</button>
</div>
</div>
<div class="circle">
<div class="img_box">
<img src="./assets/user.jpg" alt="">
</div>
</div>
</div>外层是card容器,视频和文本内容区域是上下布局的,分别使用box容器包裹,最后是circle容器包裹头像在定位在中间左边超出;
注:
video设置属性:静音(muted)可实现自动播放(autoplay),接着设置循环播放(loop);
img>和video>的父容器是一个类名img_box;
接下来,我们将使用CSS来为个人主页介绍卡片添加样式。以下是一些关键的样式属性和技巧,可以使卡片看起来更加漂亮和吸引人;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--clr: #083d41
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: var(--clr);
}
.card {
background-color: var(--clr);
position: relative;
width: 320px;
height: 430px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
/* 先把容器基本样式调整一下 */
.card .box {
background-color: tomato;
position: relative;
width: 110%;
height: 200px;
/* 文本内容区域圆角 */
border-radius: 20px;
}
/* 头像容器则使用定位布局 */
.card .circle {
width: 180px;
height: 180px;
position: absolute;
left: -70px;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
border: 10px solid var(--clr);
}
/* 调整img和video共有的父容器样式 */
.card .box .img_box,
.card .circle .img_box {
position: absolute;
inset: 0;
overflow: hidden;
/* img的圆角 */
border-radius: 50%;
}
.card .box .img_box {
/* video的圆角 */
border-radius: 15px;
}
/* 调整图片和视频的样式 */
.card .box .img_box video,
.card .circle .img_box img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}调整card下的第一个box容器样式,也就是包裹视频的容器:
.card .box:nth-child(1)::before {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
z-index: 10;
top: 106px;
left: -1px;
border-bottom-left-radius: 20px;
box-shadow: -6px 6px var(--clr);
}
/* 样式同before类似,注意定位样式 */
.card .box:nth-child(1)::after {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
z-index: 10;
bottom: -1px;
left: 105px;
border-bottom-left-radius: 20px;
box-shadow: -6px 6px var(--clr);
}目前添加样式效果图,可以在调试阶段更改明显色彩用于调整距离、位置等;
调整card下的第二个box容器样式,也就是包含文字信息的容器:
.card .box:nth-child(2) {
background-color: #fff;
width: 100%;
height: 220px;
}
.card .box:nth-child(2)::before {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
z-index: 10;
bottom: 106px;
left: -1px;
border-top-left-radius: 20px;
box-shadow: -6px -6px var(--clr);
}
.card .box:nth-child(2)::after {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
z-index: 10;
top: -1px;
left: 109px;
border-top-left-radius: 20px;
box-shadow: -6px -6px var(--clr);
}
.card .box .content {
position: absolute;
inset: 0;
padding: 30px 10px 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
/* 姓名和Title样式 */
.card .box .content h2 {
width: 100%;
padding-left: 120px;
text-transform: uppercase;
letter-spacing: 0.1em;
line-height: 1.1em;
font-size: 1.15em;
font-weight: 600;
color: #333;
}
.card .box .content h2 span {
letter-spacing: 0.05em;
font-size: 0.75em;
font-weight: 400;
color: tomato;
text-transform: initial;
}
/* 列表样式 */
.card .box .content ul {
position: relative;
top: 15px;
width: 100%;
padding: 0 10px;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.card .box .content ul li {
list-style: none;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 10px;
font-size: 0.85em;
font-weight: 500;
color: #999;
}
.card .box .content ul li:not(:last-child)
{
border-right: 1px solid #ccc;
}
.card .box .content ul li span{
font-size: 1.65em;
color: #333;
}
/* 按钮样式 */
.card .box .content button {
position: relative;
top: 25px;
padding: 8px 30px;
border: none;
outline: none;
background-color: #03a9f4;
border-radius: 30px;
color: #fff;
font-size: 1em;
letter-spacing: 0.2em;
text-transform: uppercase;
font-weight: 500;
cursor: pointer;
border: 5px solid var(--clr);
box-shadow: 0 0 0 10px #fff;
transition: .5s;
}
.card .box .content button:hover {
letter-spacing: 0.5em;
background-color: #ff3d7f;
}由于按钮的圆角与文本内容卡片的交界处看上去显得有些过于突兀了; 所以现在把它们的交界处优化成弧形,样式类似box的伪元素,这里也给按钮创建两个伪元素,用于优化两边的交界处:
.card .box .content button::before {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
top: 23px;
left: -29px;
border-top-right-radius: 20px;
box-shadow: 5px -7px #fff;
}
.card .box .content button::after {
content: "";
width: 20px;
height: 20px;
background-color: transparent;
position: absolute;
top: 23px;
right: -29px;
border-top-left-radius: 20px;
box-shadow: -5px -7px #fff;
}除了基本样式之外,还进一步优化个人主页介绍卡片的细节。一些可选的技巧包括:
通过运用CSS的各种样式属性和技巧,我们可以轻松地创建漂亮的个人主页介绍卡片。这些卡片不仅能够有效地展示个人信息和技能,还能够吸引访客的注意力并提供良好的用户体验。记得尝试不同的样式和效果来定制你自己独特的个人主页卡片!
CSS创作个人主页介绍卡片,展示独特魅力
原文链接:https://juejin.cn/post/7260709771870060603
加完用户提交博客内容的代码之后,应用程序看起来比任何时候都要好,但是还是有个问题。我们把所有关注者的 blog 展示在首页上。如果数量超过上千的话会发生些什么?或者上百万?你可以想象得到,处理如此大数据量的列表对象将会及其低效的。
相反,如果我们分组或者分页显示大量的 blog?效率和效果会不会好一些了?
Flask-SQLAlchemy 天生就支持分页。比如如果我们想要得到用户关注者的前三篇 blog,我们可以这样做:
posts = g.user.followed_posts().paginate(1, 3, False).items
paginate 方法能够被任何查询调用。它接受三个参数:
页数,从 1 开始,
每一页的项目数,这里也就是说每一页显示的 blog 数,
错误标志。如果是 True,当请求的范围页超出范围的话,一个 404 错误将会自动地返回到客户端的网页浏览器。如果是 False,返回一个空列表而不是错误。
从 paginate 返回的值是一个 Pagination 对象。这个对象的 items 成员包含了请求页面项目(本文是指 blog)的列表。在 Pagination 对象中还有其它有帮助的东西,我们将在后面能看到。
现在让我们想想如何在我们的 index 视图函数中实现分页。我们首先在配置文件中添加一些决定每页显示的 blog 数的配置项(文件 config.py):
# paginationPOSTS_PER_PAGE = 3
在最后的应用程序中我们当然会使用每页显示的 blog 数大于 3,但是测试的时候用小的数量更加方便。
接着,让我们看看不同页的 URLs 是什么样的。我们知道 Flask 路由可以携带参数,因此我们在 URL 后添加一个后缀表示所需的页面:
http://localhost:5000/ <-- page #1 (default) http://localhost:5000/index <-- page #1 (default) http://localhost:5000/index/1 <-- page #1 http://localhost:5000/index/2 <-- page #2
这种格式的 URLs 能够轻易地通过在我们的视图函数中附加一个 route 来实现(文件 app/views.py):
我们新的路由需要页面数作为参数,并且声明为一个整型。同样我们也需要在 index 函数中添加 page 参数,并且我们需要给它一个默认值。
现在我们已经有可用的页面数,我们能够很容易地把它与配置中的 POSTS_PER_PAGE 一起传入 followed_posts 查询。
现在试试输入不同的 URLs,看看分页的效果。但是,需要确保可用的 blog 数要超过三个,这样你就能够看到不止一页了!
我们现在需要添加链接允许用户访问下一页以及/或者前一页,幸好这是很容易做的,Flask-SQLAlchemy 为我们做了大部分工作。
我们现在开始在视图函数中做一些小改变。在我们目前的版本中我们按如下方式使用 paginate 方法:
posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False).items
通过上面这样做,我们可以获得返回自 paginate 的 Pagination 对象的 items 成员。但是这个对象还有很多其它有用的东西在里面,因此我们还是使用整个对象(文件 app/views.py):
posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False)
为了适应这种改变,我们必须修改模板(文件 app/templates/index.html):
<!-- posts is a Paginate object -->
{% for post in posts.items %}
<p>
{{post.author.nickname}} says: <b>{{post.body}}</b>
</p>
{% endfor %}这个改变使得模版能够使用完全的 Paginate 对象。我们使用的这个对象的成员有:
has_next:如果在目前页后至少还有一页的话,返回 True
has_prev:如果在目前页之前至少还有一页的话,返回 True
next_num:下一页的页面数
prev_num:前一页的页面数
有了这些元素后,我们产生了这些(文件 app/templates/index.html):
因此,我们有了两个链接。第一个就是名为 “Newer posts”,这个链接使得我们能够访问上一页。第二个就是 “Older posts”,它指向下一页。
当我们浏览第一页的时候,我们不希望看到有上一页的链接,因为这时候是不存在前一页。这是很容易被监测的,因为 posts.has_prev 会是 False。我们简单地处理这种情况,当用户浏览首页的时候,上一页会显示出来,但是不会有任何的链接。同样,下一页也是这样的处理方式
*请认真填写需求信息,我们会在24小时内与您取得联系。