七、JS项目实战
大约 21 分钟约 6357 字
(一)文字滚动效果
1.编写 JS 前需考虑
- 初始化:一开始要做什么
- 交互:用户操作之后要做什么
(二)手风琴效果
规范
DRY:don't repeat yourself
能封装成模块的功能函数尽量抽离出来
1.JS 动画函数
- 动画的本质:从一个值变化到另一个值
function createAnimation(options) {
var from = options.from; // 起始值
var to = options.to; // 结束值
var totalMS = options.totalMS || 1000; // 变化总时间
var duration = options.duration || 15; // 动画间隔时间
var times = Math.floor(totalMS / duration); // 变化的次数
var dis = (to - from) / times; // 每一次变化改变的值
var curTimes = 0; // 当前变化的次数
var timerId = setInterval(function () {
from += dis;
curTimes++; // 当前变化增加一次
if (curTimes >= times) {
// 变化的次数达到了
from = to; // 变化完成了
clearInterval(timerId); // 不再变化了
options.onend && options.onend();
}
// 无数的可能性 —— 回调模式
options.onmove && options.onmove(from);
}, duration);
}
2.回调模式
- 满足以下两点即可使用回调模式
- 事件函数知道什么时候处理,但不知道怎么处理
- 绑定事件的对象知道怎么处理,但不知道什么时候处理
- 通过回调函数参数交互
(三)动态排序表格效果
1.localeCompare
- localeCompare 是一种基于国际化字体的地区字符比较
- 例如中国用中文,美国用英文,法国用法文,德国用德文......
- 将这些国家的文字按照国家/地区等进行编号,然后每个编号都对应了该国/地区的文字
- 传入两个参数:
- 参数 1:待比较的字符串
- 参数 2:字符串文字对应的国家/地区的编号
- 返回值:
- 正数:参数 1 顺序排在调用的变量之前
- 负数:参数 1 顺序排在调用的变量之后
- 零:参数 1 和调用的变量相等,顺序不分先后
var val1 = "张三",
val2 = "李四他爸爸";
val1.localeCompare(val2, "zh");
2.appendChild
parentNode.appendChild(chileNode)
方法将一个节点附加到指定父节点的子节点列表的末尾处- 如果将被插入的节点已经存在于当前文档的文档树中【即原本就是该父节点的一个子节点】
- 那么 appendChild() 只会将它从原先的位置移动到新的位置
- 不需要事先移除要移动的节点
(四)三级联动效果
1.中国各省市大学名称【2017 年整理】
- 省会字典
- 标号:省市名称
- 城市字典
- 省标号:{ 城市标号:城市名称 }
- 学校字典
- 城市标号:[大学 1, 大学 2]
(五)腾讯视频重磅推荐模块
1.使用自定义属性
- 在初始化标题列表的同时绑定 id 值
- 便于后续绑定事件
// 绑定自定义属性
var el = document.querySelector(".menu-item[data-index='" + id + "']");
// 获取自定义属性值
changeVideoContent(this.getAttribute("data-index"));
(六)图片放大镜
1.大图移动距离
- 其实就是放大镜的 top、left 的距离
- 需要取负值
// 放大镜偏移
mirror.style.left = newX + "px";
mirror.style.top = newY + "px";
// 大图移动
bigImg.style.backgroundPosition = `${-newX}px ${-newY}px`;
(七)积分抽奖效果
1.奖品顺时针高亮的效果
- 按奖品数组顺序遍历
- 每次去除上一个奖品的高亮样式,再为当前奖品添加高亮样式
- 因此奖品需要使用固定定位,排列成一周
- 不能使用正常的文档流定位
prizes[currentActive].classList.remove("active");
var nextActive = (currentActive + 1) % prizes.length;
prizes[nextActive].classList.add("active");
currentActive = nextActive;
2.定时器 Bug
- 多次点击抽奖按钮会开启多个定时器,导致抽奖函数多次执行
- 需要做防抖
var timer = null;
function playLotteryOnce() {
if (currentCount < totalCount) {
if (timer) clearInterval(timer);
timer = setInterval(() => {
// ...
}, 50);
}
}
lotteryBtn.addEventListener("click", playLotteryOnce);
(八)JS 倒计时效果
1.transition 属性
1)作用
- 从一种状态过渡到另一种状态
- 用于在一定的时间内进行元素平滑的过渡
- 这种效果可以在元素被单击,鼠标滑过,或者是其他的事件中触发,实现圆滑的以动画效果改变 CSS 属性的效果
2)子属性
- transition 属性是个复合属性
属性名 | 含义 |
---|---|
transition-property | 规定设置过渡效果的 css 属性名称,常用值 all:全部 css 属性进行动画效果添加 |
transition-duration | 规定完成过渡效果需要多少秒或毫秒 |
transition-timing-function | 指定过渡函数,规定速度效果的速度曲线 常用值(关键字描述):linear ease-in ease-in-out |
transition-delay | 指定开始出现的延迟时间 |
3)使用方法
- hover 效果实现
div {
width: 200px;
height: 200px;
background-color: red;
transition: all 0.2s linear; // all => 全部执行 200毫秒内执行完成 以线性方式执行
}
div:hover {
background-color: yellow;
}
- 以事件的形式进行 trainstion 属性添加
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
left: 200px;
top: 0px;
}
</style>
</head>
<body>
<div class="box"></div>
<button id="btn">点击进行transtion属性添加</button>
<script>
document.getElementById("btn").addEventListener("click", function () {
var box = document.getElementsByClassName("box")[0];
box.style.transition = "all .5s linear";
box.style.backgroundColor = "yellow";
box.style.top = "200px";
});
</script>
</body>
</html>
2.动画结束事件 transitionend
- 当动画执行完成之后,dom 元素会触发 transitionend 事件
var firstChild = el.querySelectorAll("li")[0];
el.style.marginTop = "-120px";
el.style.transition = "all 0.1s linear";
el.addEventListener("transitionend", function () {
el.style.marginTop = "0px";
el.style.transition = "none";
el.appendChild(firstChild);
});
3.倒计时效果
- 为时、分、秒的十位和个位分别开启定时器
- 通过定时器的时间间隔模拟倒计时
handleChangeTime(document.querySelector("#hour_ten"), 1000 * 60 * 60 * 3);
handleChangeTime(document.querySelector("#hour_one"), 1000 * 60 * 60);
handleChangeTime(document.querySelector("#minute_ten"), 1000 * 60 * 10);
handleChangeTime(document.querySelector("#minute_one"), 1000 * 60);
handleChangeTime(document.querySelector("#second_ten"), 1000 * 10);
handleChangeTime(document.querySelector("#second_one"), 1000);
(九)无缝轮播图
1.动画函数(ver 2.0)
- 如果有 onend 函数
- 先执行 onmove 函数
- 再执行 onend 函数
- 最后结束本次函数调用
function createAnimation(options) {
var from = options.from;
var to = options.to;
var totalMS = options.totalMS || 1000;
var duration = options.duration || 15;
// 计算动画变化的次数
var times = Math.floor(totalMS / duration);
// 计算数字每次动画变化多少
var dis = (to - from) / times;
// 当前变化次数
var curTime = 0;
var timer = setInterval(() => {
from += dis;
curTime++;
if (curTime >= times) {
from = to;
clearInterval(timer);
options.onmove && options.onmove(from);
options.onend && options.onend();
return;
}
options.onmove && options.onmove(from);
}, duration);
}
(十)图片瀑布流
1.什么是瀑布流
- 瀑布流,又称瀑布流式布局
- 是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局
- 随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部
2.制作思路
1)瀑布流图片都是定宽不定高的
- 定宽,就能计算出一共显示几列
- 得到列数后,用一个数组保存每一行的高度
- 按照 4 列来算,一开始一张图片都没有放,每一列的高度都为 0,所以数组里面是 4 个 0
2)铺满第一行
- 放入第一张图片,找数组里面最小的,目前都是 0,就放在第一列
- 放完之后需要更新数组里面的最小值
- 依此类推,找数组最小的,会找到第二个 0,往第二列放入图片
- 更新数组,找到第三个 0,往第三列放入图片
- 更新数组...
3)铺满下一行
- 第一行满了,该放在第二行了,但是放在第二行的第几列呢?
- 实际上和上面的算法是一样的,找数组的最小值即可
- 哪个最小就放在哪一列,放完之后更新数组
新的高度的计算公式
这一列新的高度 = 这一列高度(数组里面存储的) + 间隙 + 新的图片高度
4)计算第几列
- 这只是计算了 top 值,还有 left 值需要计算
- 每张图片的 left 值只和 该图片所在的列 有关
3.函数防抖
- 图片已经按照瀑布流的形式布局出来了
- 当我们改变窗体大小的时候,图片需要重新进行布局
- 要监听 widnow 的 resize 事件
- 每当此事件触发时,就需要重新排列
警告
布局函数是一个耗时长且复杂的函数,频繁触发 reflow 会极大影响用户体验
并且 resize 过程中无需触发重新布局,resize 结束后再根据最后窗口大小重新布局
需要使用函数防抖
var timeId = null; // 一个计时器的 id
// 主要就是绑定窗口尺寸改变的监听事件
window.onresize = function () {
if (timeId) {
clearTimeout(timeId);
}
timeId = setTimeout(function () {
setPositions(); // 重新排列
}, 500);
};
(十一)分页插件
1.什么是分页
2.如何制作分页
3.createPager 的实现
1)【首页】、【上一页】、【下一页】、【尾页】
- 这四个按钮分为能够点击和不能点击两种情况
2)中间数字页码
- 中间的数字会有一个边界,要先把这个边界找出来
- min 最小数字的计算方式:
- max 最大数字的计算方式:
- 在从最小数字到最大数字的循环中,如果 i 等于 page,那么说明是当前页,挂上 active 样式类
4.分页跳转
- 跳转的本质,其实就是重新调用 createPager
- 传递新的页码,其他参数不变
- 跳转完成后,后续还需要发送请求从服务器上面获取对应页码的数据
(十二)五子棋游戏
1.HTML5 新增查询 API
- querySelector
- 只会选择匹配的第一个元素
- querySelectorAll
- 会选择所有匹配的元素
// 模拟 jquery 封装两个查询方法:
function $(selector) {
return document.querySelector(selector);
}
function $$(selector) {
return document.querySelectorAll(selector);
}
2.模板字符串
- 模板字符串使用反引号 (``) 来代替普通字符串中的双引号和单引号
- 模板字符串可以包含特定语法(
${expression}
)的占位符
var name = "xiejie";
console.log(`Hello,${name}`);
- 以前使用字符串拼接
var chessPoint = {
c: "white",
x: 2,
y: 3,
};
var newChess = "<div style='' class='chess " + chessPoint.c + "' data-row='" + chessPoint.y + "' data-line='" + chessPoint.x + "'></div>";
// <div class='chess white' data-row='3' data-line='2'></div>
- 现在使用字符串模板
var chessPoint = {
c: "white",
x: 2,
y: 3,
};
var newChess = `<div class='chess ${chessPoint.c}' data-row='${chessPoint.y}' data-line='${chessPoint.x}'></div>`;
3.clientWidth
Element.clientWidth
属性表示元素的内部宽度,单位是像素- 该属性包括内边距
padding
- 但不包括边框
border
、外边距margin
和垂直滚动条(如果有的话)
4.棋盘的绘制
- 绘制棋盘,其实就是一个 14 行 x 14 列 的 table 表格
- 每个 td 会记录当前的格子是第几行第几列【通过 自定义属性 来进行记录】
data-row
记录行data-line
记录列
1)第一行第一列
2)第一行最后一列
3)最后一行第一列
4)最后一行最后一列
5.确定落子的坐标
- 当用户在棋盘上点击鼠标时,需要落下一颗棋子
1)获取点击的 td
e.target.dataset
能够获取到用户点击的是哪一个 td
{ "row": "0", "line": "0" }
2)判断落子位置
- 落子是落在两条线的交叉处的,而不是格子中央
- 这意味着同样一个 td 格子,用户点击的位置不同,则棋子的位置也不同
e.offsetX
、e.offsetY
可以获取到事件发生时鼠标相对于 事件源元素 的坐标- 所谓事件源元素就是绑定事件的那个元素
- 首先计算出一个格子的宽高
- 然后用户点击的 e.offsetX 小于格子宽度的一半,e.offsetY 小于格子高度的一半,则是左上区域
- e.offsetX 小于格子宽度的一半,但是 e.offsetY 大于格子高度的一半,则是左下
- 依此类推
//定位落子的位置是在四个角的哪一个
var positionX = e.offsetX > tdw / 2;
var positionY = e.offsetY > tdw / 2;
// 生成点击的坐标点,包含 3 个属性
// x 坐标、y 坐标和 c 落子方
var chessPoint = {
x: positionX ? parseInt(temp.line) + 1 : parseInt(temp.line),
y: positionY ? parseInt(temp.row) + 1 : parseInt(temp.row),
c: whichOne,
};
- 重新组装格子信息,得到类似于下面的对象
{x: 0, y: 0, c: "white"} // 第一个格子左上
{x: 1, y: 0, c: "black"} // 第一个格子右上
{x: 0, y: 1, c: "white"} // 第一个格子左下
{x: 1, y: 1, c: "white"} // 第一个格子右下
6.绘制棋子
- 绘制棋子其实就是在 td 单元格里面添加一个 div
- 例如第一行第一个棋子
<td data-row="0" data-line="0">
<div data-row="0" data-line="0" style="" class="white"></div>
</td>
- 需要注意的是每一行和每一列的最后两个棋子共用一个单元格
- 例如第一行最后两个棋子
<td data-row="0" data-line="13">
<!-- 最后一个棋子 -->
<div data-row="0" data-line="14" style="left: 50%;" class="black"></div>
<!-- 倒数第二个棋子 -->
<div data-row="0" data-line="13" style="" class="white"></div>
</td>
- 所以最右下角的格子,会放 4 个 div
<td data-row="13" data-line="13">
<div data-row="13" data-line="13" style="" class="white"></div>
<div data-row="13" data-line="14" style="left: 50%;" class="black"></div>
<div data-row="14" data-line="13" style="top: 50%;" class="white"></div>
<div data-row="14" data-line="14" style="top: 50%; left: 50%;" class="black"></div>
</td>
7.胜负判定
- 每一次落子都需要判断
- 每一次落子都将这个棋子的坐标对象存储入数组
- 每次落子遍历数组进行判断即可
- 核心代码块
// 检查横着有没有连着的 5 个
chess2 = chessArr.find(function (item) {
return curChess.x === item.x + 1 && item.y === curChess.y && item.c === curChess.c;
});
chess3 = chessArr.find(function (item) {
return curChess.x === item.x + 2 && item.y === curChess.y && item.c === curChess.c;
});
chess4 = chessArr.find(function (item) {
return curChess.x === item.x + 3 && item.y === curChess.y && item.c === curChess.c;
});
chess5 = chessArr.find(function (item) {
return curChess.x === item.x + 4 && item.y === curChess.y && item.c === curChess.c;
});
if (chess2 && chess3 && chess4 && chess5) {
end(curChess, chess2, chess3, chess4, chess5);
}
// 检查竖着有没有连着的 5 个
chess2 = chessArr.find(function (item) {
return curChess.x === item.x && item.y + 1 === curChess.y && item.c === curChess.c;
});
chess3 = chessArr.find(function (item) {
return curChess.x === item.x && item.y + 2 === curChess.y && item.c === curChess.c;
});
chess4 = chessArr.find(function (item) {
return curChess.x === item.x && item.y + 3 === curChess.y && item.c === curChess.c;
});
chess5 = chessArr.find(function (item) {
return curChess.x === item.x && item.y + 4 === curChess.y && item.c === curChess.c;
});
if (chess2 && chess3 && chess4 && chess5) {
end(curChess, chess2, chess3, chess4, chess5);
}
// 检查斜线 1 有没有连着的 5 个
chess2 = chessArr.find(function (item) {
return curChess.x === item.x + 1 && item.y + 1 === curChess.y && item.c === curChess.c;
});
chess3 = chessArr.find(function (item) {
return curChess.x === item.x + 2 && item.y + 2 === curChess.y && item.c === curChess.c;
});
chess4 = chessArr.find(function (item) {
return curChess.x === item.x + 3 && item.y + 3 === curChess.y && item.c === curChess.c;
});
chess5 = chessArr.find(function (item) {
return curChess.x === item.x + 4 && item.y + 4 === curChess.y && item.c === curChess.c;
});
if (chess2 && chess3 && chess4 && chess5) {
end(curChess, chess2, chess3, chess4, chess5);
}
// 检查斜线 2 有没有连着的 5 个
chess2 = chessArr.find(function (item) {
return curChess.x === item.x - 1 && item.y + 1 === curChess.y && item.c === curChess.c;
});
chess3 = chessArr.find(function (item) {
return curChess.x === item.x - 2 && item.y + 2 === curChess.y && item.c === curChess.c;
});
chess4 = chessArr.find(function (item) {
return curChess.x === item.x - 3 && item.y + 3 === curChess.y && item.c === curChess.c;
});
chess5 = chessArr.find(function (item) {
return curChess.x === item.x - 4 && item.y + 4 === curChess.y && item.c === curChess.c;
});
if (chess2 && chess3 && chess4 && chess5) {
end(curChess, chess2, chess3, chess4, chess5);
}
(十三)读心术小游戏
1.弹性盒子
- 2009 年,W3C 提出了一种新的方案 —— flex 布局
- 可以简便、完整、响应式地实现各种页面布局
- 目前已经得到了所有浏览器的支持
- flex 布局已经成为当前布局的首选方案
1)生成弹性容器和弹性项目
2)更改方向
- 通过
flex-direction
可更改主轴方向
3)主轴排列
- 通过
justify-content
可以影响主轴的排列方式
4)侧轴排列
- 通过
align-items
可以影响侧轴的排列方式
2.网格布局
- grid 布局与 flex 布局有一定的相似性,都可以指定容器内部多个项目的位置
- flex 布局是轴线布局,只能指定“项目”针对轴线的位置,可以看作是一维布局
- grid 布局则是将容器划分成“行”和“列”,产生单元格,然后指定“项目所在”的单元格,可以看作是二维布局
- grid 布局远比 flex 布局强大
1)display 属性
display: grid
可以指定一个容器采用网格布局- 默认情况下,所指定的容器元素为块级元素
- 也可以通过
display: inline-grid
将其设成行内元素
<body>
<span>foo</span>
<div class="wrapper">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
<span>bar</span>
</body>
.wrapper {
width: 450px;
height: 450px;
background: #f3f3f3;
text-align: center;
display: grid;
grid-template-columns: 150px 150px 150px;
grid-template-rows: 150px 150px 150px;
}
.item {
text-align: center;
border: 1px solid #fff;
color: #fff;
font-weight: bold;
line-height: 150px;
}
.item:first-of-type {
background: #ef342a;
}
.item:nth-of-type(2) {
background: #00a0a0;
}
.item:nth-of-type(3) {
background: #a0a0ff;
}
.item:nth-of-type(4) {
background-color: skyblue;
}
.item:nth-of-type(5) {
background-color: greenyellow;
}
.item:last-of-type {
background-color: pink;
}
2)grid-template-rows 和 grid-template-columns 属性
- 容器指定了网格布局以后,接着就要划分行和列
grid-template-columns
属性定义每一列的列宽grid-template-rows
属性定义每一行的行高
- 指定了一个 3 行 3 列的网格,列宽和行高都是 150px
.wrapper {
width: 450px;
height: 450px;
background: #f3f3f3;
text-align: center;
display: grid;
grid-template-columns: 150px 150px 150px;
grid-template-rows: 150px 150px 150px;
}
- 除了使用绝对单位,也可以使用百分比
.wrapper {
width: 450px;
height: 450px;
background: #f3f3f3;
text-align: center;
display: grid;
grid-template-columns: 33.33% 33.33% 33.33%;
grid-template-rows: 33.33% 33.33% 33.33%;
}
- 通过
grid-template-columns
属性和百分比值的配合可以很轻松的写出两栏式布局
.wrapper {
width: 450px;
height: 450px;
background: #f3f3f3;
text-align: center;
display: grid;
grid-template-columns: 70% 30%;
}
3)repeat 方法
- 可以使用 repeat 函数,简化重复的值
.wrapper {
width: 450px;
height: 450px;
background: #f3f3f3;
text-align: center;
display: grid;
grid-template-columns: repeat(3, 150px);
grid-template-rows: repeat(3, 150px);
}
repeat
方法接受两个参数- 第一个参数是重复的次数
- 第二个参数是所要重复的值
- 也可以重复某种模式
/* 定义了 6 列,第一列和第四列的宽度为 100px,第二列和第五列为 20px,第三列和第六列为 80px */
grid-template-columns: repeat(2, 100px 20px 80px);
4)示例
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
width: 500px;
height: 500px;
border: 1px solid;
display: grid;
grid-template-columns: repeat(2, 250px);
grid-template-rows: 200px 200px;
}
.container div {
border: 1px solid;
text-align: center;
font-size: 18px;
line-height: 100px;
}
</style>
</head>
<body>
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
</body>
3.CSS 过渡效果
- 在 CSS3 中,新增了过渡效果,可以在样式切换时更加的丝滑,不至于两个样式之间切换很生硬
1)transition
transition: property duration timing-function delay;
- 是复合属性,包括以下几个子属性:
- transition-property :规定设置过渡效果的 css 属性名称
- transition-duration :规定完成过渡效果需要多少秒或毫秒
- transition-timing-function :指定过渡函数,规定速度效果的速度曲线
- transition-delay :指定开始出现的延迟时间
2)示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
transition: all 1s;
}
div:hover {
height: 300px;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
4.CSS 变形
- CSS 变形 transform 是一些效果的集合
- 主要是移动、旋转、缩放和倾斜这四种基本操作
- 还可以通过设置 matrix 矩阵来实现更复杂的效果
- 变形 transform 可以实现 2D 和 3D 两种效果
1)旋转 ratate 函数
- 通过指定的角度参数使元素相对原点进行旋转
- 主要在二维空间内进行操作,设置一个角度值,用来指定旋转的幅度
- 如果这个值为 正值 ,元素相对原点中心 顺时针 旋转
- 如果这个值为 负值 ,元素相对原点中心 逆时针 旋转
- transform:rotate(-20deg)
2)扭曲 skew 函数
- 能够让元素 倾斜显示
- 可以将一个对象以其中心位置围绕着 X 轴 和 Y 轴 按照一定的角度倾斜
- 这与 rotate()函数的旋转不同,rotate()函数只是旋转,而不会改变元素的形状
- skew()函数不会旋转,而只会改变元素的形状
- 一个参数:表示水平方向的倾斜角度
- 两个参数:第一个参数表示水平方向的倾斜角度,第二个参数表示垂直方向的倾斜角度
- 分 3 种情况
- transform:skewX(30deg)
- transform:skewY(10deg)
- transform:skew(-45deg)
3)缩放 scale 函数
- 让元素根据中心原点对对象进行缩放
- scale() 的取值默认的值为 1
- 当值设置为 0.01 到 0.99 之间时,作用使一个元素缩小
- 而任何大于或等于 1.01 的值,作用是让元素放大
- 分 3 种情况
- transform:scale(x,y)
- 使元素水平方向和垂直方向同时缩放
- transform:scale(x)
- X 轴缩放
- transform:scale(y)
- Y 轴缩放
4)位移 translate 函数
- 可以将元素向指定的方向移动,类似于 position 中的 relative
- 简单理解为,使用 translate()函数,可以把元素从原来的位置移动,而不影响在 X、Y 轴上的任何 Web 组件
- 分为三种情况:
- transform:translate(x,y)
- 使元素水平方向和垂直方向同时移动
- transform:translateX(x)
- 使元素水平方向移动
- transform:translateY(y)
- 使元素垂直方向移动
5)原点 transform-origin
- 任何一个元素都有一个中心点
- 默认情况之下,其中心点是居于元素 X 轴和 Y 轴的 50%处
- 在没有重置 transform-origin 改变元素原点位置的情况下,CSS 变形进行的旋转、位移、缩放,扭曲等操作都是 以元素自己中心位置进行变形
- 可以通过 transform-origin 来对元素进行原点位置改变,使元素原点不在元素的中心位置,以达到需要的原点位置
- transform-origin 取值和元素设置背景中的 background-position 取值类似(也可以是具体的像素值)
5.随机数
- 游戏原理:任意一个两位数,分别减去其十位数和个位数,得到的都是 9 的倍数
- 利用随机数,每次从图片列表中选一张图片,作为 9 的倍数对应的结果图片
1)产生随机数
Math.floor(Math.random() * 可能性数 + 第一个可能值);
// 例如,生成 1-10 的随机数
Math.floor(Math.random() * 10 + 1);
2)封装一个函数
// 返回从 min 到 max 的随机数
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
6.transitionend
- 该事件会在 transition 过渡效果结束后触发
- 通常该事件绑定后要在适当时候移除
- 否则下一次 transition 会直接触发
function handleTransitionEnd() {
roundImage.style.opacity = 0;
isGameOver = true;
}
roundContainer.addEventListener("transitionend", handleTransitionEnd);
(十四)图片拖动验证
1.CSS sprite 精灵图
- CSS Sprite,雪碧图或精灵图,它是一种图像拼合技术
- 该方法是将小图标和背景图像合并到一张图片上,然后利用 css 的背景定位来显示需要显示的图片部分
- 雪碧图的使用有以下几个优点:
- 减少图片的字节
- 减少网页的 http 请求,从而大大的提高页面的性能
- 解决了网页设计师在图片命名上的困扰,只需对一张集合的图片上命名就可以了,不需要对每一个小元素进行命名,从而提高了网页的制作效率
- 更换风格方便,只需要在一张或少张图片上修改图片的颜色或样式,整个网页的风格就可以改变,维护起来更加方便
/* 语法 */
background-position: npx npx;
- 第一个值是调左右的,当需要将背景图向右调的时候用正值,向左则为负值
- 同理将背景图上下调动的时候上是用负值,下是正值
2.拖动按钮的距离计算
- 原理:空缺图块必须出现在容器宽度的右半侧才能拖动
- 如何计算拖动按钮的距离
- 用户之所以可以按住按钮实时的进行滑动,实际上就是在不停的修改按钮的 left 值
- 那么 实时的得到按钮最新的 left 值 就是一个非常重要的点
重要
按钮实时的 left 值 = 滑条的 clientX - 滑条的 offsetLeft - 按钮的 offsetX