本文是https://www.bilibili.com/video/BV1nGDsYzEZX/?spm_id_from=333.337.search-card.all.click
的笔记
一个可以拖拽的div
html
<!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>
.container {
width: 100%;
height: 600px;
border: 1px solid red;
position: relative;
}
.mover {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
user-select: none;
}
</style>
</head>
<body>
<div class="container" id="container">
</div>
<script>
let num = 0;
let canMove = false;
let divOffsetLeft = 0;
let divOffsetTop = 0;
function init() {
const container = document.getElementById("container");
// 绑定 onmousedown 事件处理函数,当用户按下鼠标时触发。
// targetDom 获取鼠标点击的目标元素。
// 如果点击的是 container 元素本身(不是其中的拖动 div),调用 createMoveDiv() 函数创建一个新的可拖动 div,并传入鼠标相对容器的 x 和 y 坐标(即 event.offsetX 和 event.offsetY)。
// 如果点击的是一个已有的 mover(可拖动的 div),则设置 canMove 为 true,表示允许拖动,并记录鼠标在 div 中的偏移量(divOffsetLeft 和 divOffsetTop)。同时,设置该 div 的 z-index 为最大,确保它处于最上层,避免被其他元素遮挡。
container.onmousedown = function (event) {
const targetDom = event.target;
if (targetDom.getAttribute('class') === 'container') {
//如果是容器就创建div
createMoveDiv(container, event.offsetX, event.offsetY);
} else if (targetDom.getAttribute('class') === 'mover') {
//如果点的是可拖动的div
canMove = true;
divOffsetLeft = event.offsetX;
divOffsetTop = event.offsetY;
event.target.style.zIndex = 999999;
//dom元素的x怎么获取
// console.log(event.target.getBoundingClientRect());
}
}
// 绑定 onmousemove 事件处理函数,当用户移动鼠标时触发。
// 如果 canMove 为 true(即用户正在拖动元素),则调用 move() 函数,将 div 移动到新的位置。
// e.pageX 和 e.pageY 获取当前鼠标相对于页面的位置。
container.onmousemove = function (e) {
if (canMove) {
//一定是在div移动时,才会触发这些东西
console.log("移动监听生效")
move(e.pageX, e.pageY, e.target);
}
}
// 绑定 onmouseup 事件处理函数,当用户松开鼠标时触发。
// 设置 canMove 为 false,停止拖动。
// 重置拖动元素的 z-index 为 100,恢复原来的层级
container.onmouseup = function (e) {
canMove = false;
e.target.style.zIndex = 100;
}
}
function createMoveDiv(contaienr, x, y) {
const _div = document.createElement("div");
_div.setAttribute("class", "mover");
_div.innerHTML = num;
_div.setAttribute('style', `left:${x}px;top:${y}px;`)
_div.onmouseleave = function () {
canMove = false;
}
contaienr.appendChild(_div);
num += 1;
}
function move(x, y, dom) {
//因为已经有style属性在div上了,所以可以直接dom.style
dom.style.left = `${x - divOffsetLeft - 8}px`
dom.style.top = `${y - divOffsetTop - 8}px`
}
init();
</script>
</body>
</html>
````<!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>
.container {
width: 100%;
height: 600px;
border: 1px solid red;
position: relative;
}
.mover {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
user-select: none;
}
</style>
</head>
<body>
<div class="container" id="container">
</div>
<script>
let num = 0;
let canMove = false;
let divOffsetLeft = 0;
let divOffsetTop = 0;
function init() {
const container = document.getElementById("container");
// 绑定 onmousedown 事件处理函数,当用户按下鼠标时触发。
// targetDom 获取鼠标点击的目标元素。
// 如果点击的是 container 元素本身(不是其中的拖动 div),调用 createMoveDiv() 函数创建一个新的可拖动 div,并传入鼠标相对容器的 x 和 y 坐标(即 event.offsetX 和 event.offsetY)。
// 如果点击的是一个已有的 mover(可拖动的 div),则设置 canMove 为 true,表示允许拖动,并记录鼠标在 div 中的偏移量(divOffsetLeft 和 divOffsetTop)。同时,设置该 div 的 z-index 为最大,确保它处于最上层,避免被其他元素遮挡。
container.onmousedown = function (event) {
const targetDom = event.target;
if (targetDom.getAttribute('class') === 'container') {
//如果是容器就创建div
createMoveDiv(container, event.offsetX, event.offsetY);
} else if (targetDom.getAttribute('class') === 'mover') {
//如果点的是可拖动的div
canMove = true;
divOffsetLeft = event.offsetX;
divOffsetTop = event.offsetY;
event.target.style.zIndex = 999999;
//dom元素的x怎么获取
// console.log(event.target.getBoundingClientRect());
}
}
// 绑定 onmousemove 事件处理函数,当用户移动鼠标时触发。
// 如果 canMove 为 true(即用户正在拖动元素),则调用 move() 函数,将 div 移动到新的位置。
// e.pageX 和 e.pageY 获取当前鼠标相对于页面的位置。
container.onmousemove = function (e) {
if (canMove) {
//一定是在div移动时,才会触发这些东西
console.log("移动监听生效")
move(e.pageX, e.pageY, e.target);
}
}
// 绑定 onmouseup 事件处理函数,当用户松开鼠标时触发。
// 设置 canMove 为 false,停止拖动。
// 重置拖动元素的 z-index 为 100,恢复原来的层级
container.onmouseup = function (e) {
canMove = false;
e.target.style.zIndex = 100;
}
}
function createMoveDiv(contaienr, x, y) {
const _div = document.createElement("div");
_div.setAttribute("class", "mover");
_div.innerHTML = num;
_div.setAttribute('style', `left:${x}px;top:${y}px;`)
_div.onmouseleave = function () {
canMove = false;
}
contaienr.appendChild(_div);
num += 1;
}
function move(x, y, dom) {
//因为已经有style属性在div上了,所以可以直接dom.style
dom.style.left = `${x - divOffsetLeft - 8}px`
dom.style.top = `${y - divOffsetTop - 8}px`
}
init();
</script>
</body>
</html>
轮播图 自动播放
html
<!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>
.container {
width: 980px;
height: 400px;
overflow: hidden;
margin: 0 auto;
position: relative;
}
.banner-wraper {
display: flex;
width: 980px;
height: 400px;
transition: all 0.4s ease-in;
}
.item {
flex: 0;
width: 980px;
height: 400px;
}
.item img {
width: 980px;
height: 400px;
}
.point-wraper {
height: 25px;
position: absolute;
bottom: 20px;
left: 50%;
width: 100px;
margin-left: -50px;
display: flex;
}
.point {
width: 25px;
height: 25px;
border-radius: 25px;
background-color: white;
}
</style>
</head>
<body>
<div class="container" id="container">
</div>
<script>
//实现了一个自动播放的图片轮播功能,同时用户可以点击圆点来手动切换图片
const imgsrc = ["./img/pic1.jpeg", "./img/pic2.jpeg", "./img/pic3.jpeg"]
class Banner {
imgArr = [];
time = 3000;
nowIndex = 0;
bannerItemWrapper = null;
timer = null;
constructor(imgarr, time) {
this.imgArr = imgarr;
this.time = time || 3500;
}
init() {
//创建轮播图片的容器
const container = document.getElementById("container");
const _banerItemWrapper = document.createElement("div")
_banerItemWrapper.setAttribute("class", "banner-wraper")
this.bannerItemWrapper = _banerItemWrapper;
//点击切换的点的容器
//创建一个 div 元素 _pointWrapper,用来放置控制轮播图切换的圆点(即用户点击的按钮)。
const _pointWrapper = document.createElement("div")
_pointWrapper.setAttribute('class', 'point-wraper')
//绑定点击切换 事件,直接给容器,根据e.target判断具体点的谁
// 给 pointWrapper 绑定点击事件,当用户点击某个圆点时:
// e.target 获取被点击的圆点元素。
// 通过 data-index 获取当前点击的圆点代表的是第几张图片(通过 data-index 属性设置)。
// 设置 this.nowIndex 为当前点击的图片索引。
// clearInterval(this.timer) 清除自动播放定时器,以便用户点击后不再自动切换图片。
// 调用 this.goNext() 来跳转到用户点击的图片。
// 最后调用 this.autoPlay() 重新启动自动播放。
_pointWrapper.onclick = (e) => {
const _dom = e.target;
//通过data-index知道这个dom代表第几张
const _targetIndex = _dom.getAttribute("data-index")
this.nowIndex = _targetIndex - 0
clearInterval(this.timer)
this.goNext();
this.autoPlay();
}
//循环创建每张轮播图
// this.imgArr.forEach 遍历图片数组,为每张图片做以下操作:
// 创建一个 div 元素 _bannerItem,将图片添加进去。
// 设置 class 为 item,将其加入到 bannerItemWrapper 中。
// 创建一个新的 div 元素 _point,作为点击切换的圆点,设置其 class 为 point。
// 设置 data-index 属性,表示当前图片的索引。
// 将所有的圆点元素 _point 添加到 pointWrapper 中。
// 最后将 _banerItemWrapper 和 _pointWrapper 都添加到 container 容器中。
this.imgArr.forEach((img, index) => {
//创建单个轮播图片
const _bannerItem = document.createElement("div");
_bannerItem.innerHTML = `<img src="${img}"/>`
_bannerItem.setAttribute("class", 'item')
_banerItemWrapper.appendChild(_bannerItem);
//把_banerItemWrapper加入容器
container.appendChild(_banerItemWrapper);
//创建点击切换的点
const _point = document.createElement("div");
_point.setAttribute("class", 'point');
//设置一个自定义属性,说明第几张
_point.setAttribute("data-index", index)
_pointWrapper.appendChild(_point);
//把_banerItemWrapper加入容器
container.appendChild(_pointWrapper)
})
this.autoPlay();
}
// 自动播放函数 autoPlay()
// autoPlay 定义了一个定时器,用于每隔 this.time 毫秒自动切换到下一张图片。
// this.nowIndex += 1:当前图片索引加 1。
// if (this.nowIndex === this.imgArr.length):当索引超出图片数组的范围时,重置为 0,从第一张图片开始。
// this.goNext():调用 goNext() 跳转到下一张图片。
autoPlay() {
this.timer = setInterval(() => {
this.nowIndex += 1;
if (this.nowIndex === this.imgArr.length) {
this.nowIndex = 0;
}
this.goNext();
}, this.time)
}
clickPlay() {
}
//下一个图片
goNext() {
this.bannerItemWrapper.setAttribute('style', `transform:translateX(-${this.nowIndex * 980}px)`)
}
}
new Banner(imgsrc, 3000).init();
</script>
</body>
</html>
给文本添加备注
html
<!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></style>
<style>
body {
padding-top: 100px;
}
.edit {
width: 800px;
height: 400px;
border: 1px solid red;
margin: 0 auto;
}
.mark {
color: red;
position: relative;
}
.popCover {
position: fixed;
z-index: 9999;
background-color: rgba(0, 0, 0, 0.4);
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.popcontent {
background-color: white;
width: 200px;
height: 200px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -100px;
}
.marktext {
display: none;
position: absolute;
left: 0;
width: 200px;
background-color: white;
color: black;
top: -20px;
z-index: 9999
}
</style>
</head>
<body>
<div class="edit" id="edit" contenteditable="true"></div>
<button id="mark">备注</button>
<div id="popCover" class="popCover" style="display: none;">
<div class="popcontent">
<h2>输入备注内容</h2>
<input id='markValue' />
<div>
<button id="confirm">确认</button>
<button id="cancel">取消</button>
</div>
</div>
</div>
<script>
let selecText = '';
function bindEvent() {
document.getElementById('mark').addEventListener("click", () => {
getSelectionText();
togglePop("show");
})
document.getElementById('confirm').addEventListener("click", () => {
togglePop("hidden");
setMark();
})
document.getElementById('cancel').addEventListener("click", () => {
togglePop("hidden");
})
document.getElementById("edit").addEventListener("click", (e) => {
if (e.target.getAttribute("class") === 'mark') {
toggleMarkContent(e.target)
}
})
}
// 这个函数用于获取用户选中的文本内容。使用 window.getSelection() 获取当前的选区,并将选中的文本转换为字符串存储在 selecText 变量中。
function getSelectionText() {
const selection = window.getSelection();
selecText = selection.toString();
}
//togglePop-切换弹窗显示映射
function togglePop(handle) {
const pop = document.getElementById('popCover');
if (handle === 'show') {
//显示弹窗
pop.style.display = 'block'
} else if (handle === 'hidden') {
//隐藏弹窗
pop.style.display = 'none';
}
}
//setMark:这个函数会将用户输入的备注内容插入到选中的文本中。具体步骤:
// 获取备注输入框的值,即用户输入的备注内容。
// 获取当前编辑区(#edit)的 HTML 内容。
// 查找选中文本的开始和结束位置。
// 分别截取选中文本之前和之后的部分。
// 将选中文本和备注内容拼接起来,并将新的 HTML 更新到编辑区中。
function setMark() {
//三个获取
//获取备注内容
const markContent = document.getElementById("markValue").value;
//获取选中内容-取selecText就好了,因为点击备注按钮时候已经存在里面了
//获取当前edit的文字
const nowHTML = document.getElementById("edit").innerHTML;
//获取选中的文本在原文中开始的位置
const start = nowHTML.indexOf(selecText)
//获取选中的文本在原文中结束的位置
const end = start + selecText.length
//截取选中文本之前的文本
const beforeSelect = nowHTML.substr(0, start)
//截取选中文本之后的文本
const afterSelect = nowHTML.substr(end, nowHTML.length);
const newHTML = beforeSelect + `<span class='mark'>${selecText}<font class='marktext'>${markContent}</font></span>` + afterSelect;
document.getElementById("edit").innerHTML = newHTML;
}
// toggleMarkContent:这个函数用于显示或隐藏某个已标记文本的备注内容。当用户点击一个已标记的文本时,会显示或隐藏备注内容(<font class='marktext'> 部分)。具体实现是遍历该文本的子元素,找到 class="marktext" 的元素,并根据其当前的显示状态切换显示与隐藏。
function toggleMarkContent(dom) {
const children = dom.children;
for (let i = 0; i < children.length; i++) {
if (children[i].getAttribute('class') === "marktext") {
if (children[i].style.display === 'block') {
children[i].style.display = 'none'
} else {
children[i].setAttribute("style", "display:block")
}
}
}
}
//调用bindEvent绑定事件
bindEvent();
</script>
</body>
</html>
`