递归dom树
rotate -transform
Array的方法
Array.prototype.flat() - JavaScript | MDN (mozilla.org)
grid布局
选择器
- [attr^="example"] 表示以^开头,[attr~="example"] 表示含有“example”属性,[attr*="example"] 含有这个字符串的属性,在任何位置都可以
[attr~=value]: 选择具有指定属性并且属性值中包含被空格分隔的指定值的元素。例如,<div class="example class">可以通过[class~=example]或[class~=class]选择器选择到。[attr|=value]: 选择具有指定属性并且属性值以指定值开头,后面跟着连字符或属性值正好是指定值的元素。例如,<div class="example">可以通过[class|=example]选择器选择到。
[attr^=value]: 选择具有指定属性并且属性值以指定值开头的元素。例如,<div class="example">可以通过[class^=ex]选择器选择到。[attr$=value]: 选择具有指定属性并且属性值以指定值结尾的元素。例如,<div class="example">可以通过[class$=ple]选择器选择到。
[attr*=value]: 选择具有指定属性并且属性值中包含指定值的元素。例如,<div class="example">可以通过[class*=exa]选择器选。- ,
[attr~=value]和[attr*=value]是两种不同的属性选择器,它们的区别如下: [attr~=value]:这是一个包含选择器(Attribute Contains Selector)。它选择具有指定属性,并且属性值中包含被空格分隔的指定值的元素。换句话说,它只会匹配属性值中包含整个指定值的元素,其中指定值可以是一个词列表,但是这些词必须以空格分隔。例如,[class~=example]选择器将会匹配<div class="example class">这样的元素,因为 "example" 是 class 属性值的一部分。[attr*=value]:这是一个包含子串选择器(Attribute Contains Substring Selector)。它选择具有指定属性,并且属性值中包含指定值的任何部分的元素。换句话说,它匹配属性值中包含指定值的任何元素,无论指定值处于属性值的哪个位置。例如,[class*=ex]选择器将会匹配<div class="example">这样的元素,因为 "example" 中包含 "ex"。
因此,[attr~=value] 匹配整个属性值中包含指定值的元素,而 [attr*=value] 匹配属性值中的任何部分包含指定值的元素。
ElementPlus
setTimeout
setTimeout函数会在指定的时间间隔后执行一次指定的函数或指定的代码。语法如下:
javascriptCopy Code
setTimeout(function, milliseconds);
其中 function 是要执行的函数或代码,milliseconds 是延迟的毫秒数。
示例:
javascriptCopy Code
setTimeout(function() {
console.log('Hello, world!');
}, 1000); // 在 1000 毫秒(1 秒)后输出 "Hello, world!"
setInterval函数会在每个指定的时间间隔后重复执行指定的函数或指定的代码。语法如下:
setInterval(function, milliseconds);
其中 function 是要执行的函数或代码,milliseconds 是时间间隔的毫秒数。
示例:
setInterval(function() {
console.log('Hello, world!');
}, 1000); // 每隔 1000 毫秒(1 秒)输出 "Hello, world!"
总的来说,setTimeout 用于在一定的延迟后执行一次代码,而 setInterval 则用于在一定的时间间隔内重复执行代码。在使用定时器时,需要注意避免产生内存泄漏和不必要的资源消耗。
布局
#box1{
display: flex;
justify-content: center;
align-items: center;
}
#box2{
display: flex;
flex-direction: column;
justify-content: space-between;
}
#box2 span:nth-child(1){
align-self: flex-start;
}
#box2 span:nth-child(2){
align-self: flex-end;
}
#box3{
display: flex;
flex-direction: column;
}
#box3 span:nth-child(1){
}
#box3 span:nth-child(2){
align-items: center;
align-self: center;
}
#box3 span:nth-child(3){
align-self: self-end;
}
#box1{
display: flex;
justify-content: center;
align-items: center;
}
#box2{
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}
#box2 span:nth-child(1){
grid-area: 1/1;
}
#box2 span:nth-child(2){
grid-area: 3/3;
}
#box2 span:nth-child(3){
grid-area: 3/3;
}
#box3{
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}
#box3 span:nth-child(1){
grid-area: 1/1;
}
#box3 span:nth-child(2){
grid-area: 2/2;
}
#box3 span:nth-child(3){
grid-area: 3/3;
}
align-self是在自己所在的小块里的位置
Object && NodeList
$(function () {
// 使用 ajax 获取 userList.json 数据并渲染到页面
getData();
const rightSelect = document.querySelector('#rightSelect')
const leftSelect = document.querySelector('#leftSelect')
// 为按钮添加事件
$("#add").click(function () {
// TODO:补充代码,实现功能\
changeAccess(true,leftSelect.querySelectorAll( 'option:checked'))
});
$("#addAll").click(function () {
// TODO:补充代码,实现功能
changeAccess(true,leftSelect.querySelectorAll('option'))
});
$("#remove").click(function () {
// TODO:补充代码,实现功能
changeAccess(false,rightSelect.querySelectorAll('option:checked'))
});
$("#removeAll").click(function () {
// TODO:补充代码,实现功能
changeAccess(false,rightSelect.querySelectorAll('option'))
});
});
/**
* 修改权限
* @param {Object} right 要修改的权限
* @param {Object} changeList 要修改权限的用户列表
*/
function changeAccess(right, changeList) {
// TODO:补充代码,实现功能
console.log(changeList,"changeList")
const tr = Array.from(document.querySelectorAll('tr'))
const ChangeL = Array.from(changeList)
Array.from(changeList).forEach(item=>{
// // 左边移到右边
// if(right){
// rightSelect.appendChild(item)
// leftSelect.removeChild(item)
// }else{
// leftSelect.appendChild(item)
// rightSelect.removeChild(item)
// } 在第一段代码中,当权限为右边时,直接将选项元素从左边的选择框移动到右边的选择框中,使用 appendChild 方法实现。但这样做会导致选项从左边移动到右边时,在左边选择框中将不再存在该选项。这意味着该选项在两个选择框中都不能存在,因为一个元素只能在文档中的一个位置存在。因此,如果你想在右边选择框中显示相同的选项,你需要在移动之前创建一个选项的副本,并将其插入到右边选择框中。
// 而在第二段代码中,通过使用 cloneNode(true) 方法创建了选项元素的一个副本,并将该副本插入到目标选择框中。这样做不仅能够保留左边选择框中的选项,还能够在右边选择框中显示相同的选项。这种方式更加安全和可靠,因为它保留了原始选项元素,并在移动时使用了它的副本。
if(right){
rightSelect.appendChild(item.cloneNode(true))
leftSelect.removeChild(item)
}else{
leftSelect.appendChild(item.cloneNode(true))
rightSelect.removeChild(item)
}
const tar = tr.filter(trItem=>{
const firstTd = trItem.querySelector('td:first-child'); // 获取当前<tr>元素下的第一个<td>元素
return firstTd.innerText===item.innerText
})
tar[0].querySelector('td:nth-child(2)').innerText = right?"管理员":"普通用户"
})
}
// 异步获取数据
async function getData() {
// TODO:补充代码,实现功能
let res = await fetch("./js/userList.json")
let data = await res.json()
data.forEach((e,i) => {
let dom =''
dom +=`
<tr>
<td>${e.name}</td>
<td>${e.right?"管理员":"普通用户"}</td>
</tr>
`
// const td1 = document.createElement('td')
// const tr = document.createElement('tr')
// const td2 = document.createElement('td')
// td1.innerText = e.name
// td2.innerHTML = e.right?"管理员":"普通用户"
// tr.appendChild(td1)
// tr.appendChild(td2)
userList.appendChild(tr)
console.log(`第${i}次`,tr,userList)
});
consolelog(data)
}
骨架屏幕 -vue递归组件
<div :class="'ske-'+paragraph.type+'-container'">
<div class="ske" v-for="item in paragraph.rows??paragraph.cols"
:class="['ske-'+item.type, {'ske-ani': active&&(item.type==='rect'||item.type==='circle')} ]"
:style="{...item?.rowStyle,...item?.colStyle,...item?.style}">
<item :paragraph="item" :active="active"></item>
</div>
</div>
Vue3 过10种组件通讯方式 - 掘金 (juejin.cn)Vue3 过10种组件通讯方式 - 掘金 (juejin.cn)
组课神器
function treeMenusRender(data, grade = 0) {
grade++;
let treeTemplate = "";
data.forEach((item) => {
treeTemplate += `
<div class="tree-node" data-index="${item.id}" data-grade="${grade}">
<div class="tree-node-content" style="margin-left: ${(grade - 1) * 15}px">
<div class="tree-node-content-left">
<img
src="./images/dragger.svg"
alt=""
class="point-svg"
/>
${item.tag ? `<span class="tree-node-tag">${item.tag}</span>` : ""}
<span class="tree-node-label">${item.label}</span>
</div>
${
item.tag
? `
<div class="tree-node-content-right">
<div class="students-count">
<span class="number"> 0人完成</span>
<span class="line">|</span>
<span class="number">0人提交报告</span>
</div>
<div class="config">
<img
class="config-svg"
src="./images/config.svg"
alt=""
/>
<button class="doc-link">编辑文档</button>
</div>
</div>`
: ""
}
</div>
</div>
${item.children ? treeMenusRender(item.children, grade) : ""}
`;
});
// TODO:根据传入的 treeData 的数据生成树型组件的模板字符串
return treeTemplate;
}
您提供的两个正则表达式都可以用于匹配文本中形如 "第X章" 的章节信息,但它们的捕获行为略有不同。
-
/第(\d)+章/g:第:匹配文本中的 "第" 字符。(\d)+:使用括号创建一个捕获分组,匹配一个或多个数字字符。括号内的\d是匹配任意数字字符的元字符,而+是匹配前面的元字符一次或多次。章:匹配文本中的 "章" 字符。/g:全局匹配标记,表示在文本中查找所有匹配项。
这个正则表达式会捕获每个匹配的数字字符,例如,在文本 "这是第3章的内容。这是第10章的内容。这是第20章的内容。" 中,它会匹配到 "3"、"10" 和 "20" 这三个数字。
-
/第\d+章/g:第:匹配文本中的 "第" 字符。\d+:匹配一个或多个数字字符。章:匹配文本中的 "章" 字符。/g:全局匹配标记,表示在文本中查找所有匹配项。
这个正则表达式不使用捕获分组,它只会匹配整个 "第X章" 字符串。在相同的文本中,它会匹配到 "第3章"、"第10章" 和 "第20章" 这三个章节信息。
因此,如果您需要捕获章节信息中的数字部分,第一个正则表达式更合适;如果只需要匹配整个章节信息,第二个正则表达式更适用。
防抖和节流
function debounce(fn, delay) {
let timer;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
function torele (fn,time){
let start = 0
return function () {
let now = Date.now()
if(now-start>time){
// fn.apply(this,arguments)
fn.call(this)
start = now
}
}
}
神操作
this.currentIndex===1 &&(this.type=1)
这段代码是一个条件语句,它检查 this.currentIndex 是否等于 1,如果是,则将 this.type 设置为 1。
这段代码通常在 Vue.js 或其他类似的前端框架中使用,其中 this 指向当前组件的实例。条件语句用于根据特定条件执行不同的操作。在这种情况下,如果 this.currentIndex 等于 1,则将 this.type 设置为 1。
天气趋势
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>天气趋势</title>
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
/>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script src="./js/axios.js"></script>
<script src="js/vue.min.js" type="text/javascript" charset="utf-8"></script>
<script
src="js/echarts.min.js"
type="text/javascript"
charset="utf-8"
></script>
</head>
<body>
<div id="app">
<div class="top-bar">2022年 Y 城全年温度统计图</div>
<!-- 主体 -->
<div class="container">
<!-- 月份 -->
<div class="month">
<ul>
<!-- TODO:待补充代码 在下面的 li 标签中完成 12个月份 (即 monthList) 的渲染 -->
<li :class="{'active':current===index}" @click="changeTab(index)" v-for="(item,key,index) in monthList" :key="index">{{item}}</li>
</ul>
</div>
<div class="chart">
<!-- TODO:待补充代码 -->
<!-- currentMonth 未来七天和本月 tab 切换,只有当前月才显示 -->
<div id="currentMonth" v-show="nowMonth===current">
<div class="title">
<h3>{{typeTitle}}</h3>
<div class="type">
<span id="seven" :class="{'active': isSevendays}" @click="handle7">未来7天</span>
<span id="current" :class="{'active': !isSevendays}" @click="handleMonth">本月</span>
</div>
</div>
</div>
<div id="chart"></div>
</div>
</div>
</div>
</body>
</html>
<script>
// TODO:待补充代码
var vm = new Vue({
el: "#app",
data: {
chart: null, // 图表
chartOptions: null, // 图表配置项
typeTitle: "本月天气",
current:0,
isSevendays:false,
data:[],
nowMonth:(new Date()).getMonth(),
monthdata: [
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,
],
monthList: {
January: "1月",
February: "2月",
March: "3月",
April: "4月",
May: "5月",
June: "6月",
July: "7月",
August: "8月",
September: "9月",
October: "10月",
November: "11月",
December: "12月",
},
},
mounted: function () {
// 初始化 echarts
axios.get("./js/weather.json").then(res=>{
// console.log(res.data,Object.values(res.data[0]),res.data[0]);
this.data = res.data
this.changeTab(0)
})
this.$nextTick(() => {
this.initChart();
});
},
methods: {
changeTab(e){
if(e===this.nowMonth){
this.isSevendays = false
}
this.current = e
let xAxisData = Object.values(this.data[this.current])[0]
this.chartOptions.xAxis[0].data = this.monthdata.slice(0,xAxisData.length)
this.chartOptions.series[0].data = xAxisData
console.log("lll",this.monthdata.slice(0,xAxisData.length));
// console.log(xAxisData[0],this.chartOptions);
this.chart.setOption(this.chartOptions);
},
handle7(){
this.isSevendays = true
this.typeTitle = "未来七天天气";
let xAxis = []
let series = []
let currentTime = new Date()
// 月份是月份nowMonth
for(let i =0;i<7;i++){
let nextDate = new Date(currentTime.getTime()+i*24*60*60*1000)
let month = nextDate.getMonth()
let date = nextDate.getDate()
let curMd = Object.values(this.data[month])[0]
let formDate = month+1 +'/' + date
xAxis.push(formDate)
series.push(curMd[date-1])
}
console.log(xAxis);
this.chartOptions.xAxis[0].data = xAxis
this.chartOptions.series[0].data =series
this.chart.setOption(this.chartOptions);
},
handleMonth(){
this.typeTitle = "本月天气";
this.isSevendays = false
this.changeTab(this.nowMonth)
},
</script>
(val,key,index) in monthList 遍历对象
在 Vue.js 中,v-for 指令可以用于遍历对象的属性。你可以像下面这样使用 v-for 来遍历对象:
<div v-for="(val, key, index) in monthList" :key="index">
{{ key }}: {{ val }}
</div>
在这个例子中,假设 monthList 是一个对象,val 表示对象的值,key 表示对象的键,index 表示当前项的索引。在 v-for 中,val、key 和 index 是由 Vue.js 提供的特殊变量,用于在遍历过程中访问对象的属性和索引。
在模板中,可以使用这些变量来显示对象的键和值。在这个例子中,每次循环,都会创建一个 <div> 元素来显示对象的键和值。:key="index" 是为了帮助 Vue.js 识别每个循环项的唯一性。