js复习--考核

1.轮播图

考点

语法:

css:position会让元素悬浮;border-radius是;active相关效果

js:

setInterval(函数,时间)----过XXms触发(不关闭就一直开着使用)

数组.push(元素)

元素.appendChild(子元素)

逻辑:

添加左右->添加渲染点 点高亮css

->函数startTimer let timer全局变量 在函数里定义为计时器 计时器内容:删,增active 实现轮播效果

->使用函数->鼠标进入(关计时)与离开函数(用函数开计时)

->左右按钮监听点击事件(关计时+删加active)

->圆点被点击 用圆点数组遍历( 传入dot和index形参 dot绑定点击事件)

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0px;
            padding: 0px;
        }
        .container{
            margin: 0 auto;
            position: relative;
            width: 1000px;
            height: 800px;
            background-color: yellow;
        }
        img{
            width: 100%;
            height: 90%;
            display: none;
        }
        .name{
            background-color: rgb(19, 19, 19);
            width: 100%;
            height: 10%;
            color: rgb(230, 226, 226);
            font-size: 20px;
            position: absolute;
            left: 0px;
            top: 90%;
            display: none;
        }
        .active{
            display: block;
        }

        .left{
            position: absolute;
            font-size: 50px;
            left: 0;
            top: 50%;
            color:white;
            cursor: pointer;
        }
        .right{
            position: absolute;
            font-size: 50px;
            right: 0;
            top: 50%;
            color: white;
            cursor: pointer;
        }
        .dots{
            position: absolute;
            left: 20%;
            top: 95%;
            z-index: 10;
        }
        .dots span{
            width: 30px;
            height: 30px;
            border-radius: 50%;
            background-color: grey;
            margin: 0 5px;
            cursor: pointer;
            display: inline-block;
        }
        span.active{
            background-color: white;
        }
    </style>
</head>
<body>
    <div class="container">
        <img src="./yushi_20.JPG" alt="" class="active">
        <div class="name active">fall'out</div>
        <img src="./yushi_10.JPG" alt="">
        <div class="name">小u</div>
        <img src="./yushi_3.png" alt="">
        <div class="name">Yushi</div>

        <div class="left">&lt;</div>
        <div class="right">&gt;</div>

        <div class="dots">
        </div>
    </div>
    <script>
        const container=document.querySelector('.container')
        const imgArr=document.querySelectorAll('img')
        const nameArr=document.querySelectorAll('.name')
        const left=document.querySelector('.left')
        const right=document.querySelector('.right')
        const dotsContainer=document.querySelector('.dots')

        for(let i=0;i<imgArr.length;i++){
            const spanEle=document.createElement('span')
            dotsContainer.appendChild(spanEle)
        }
        
        const dots = document.querySelectorAll('.dots span')
        dots[0].classList.add('active')


        //轮播->active删+增 定时器
        let currentIndex=0
        let timer
        function startTimer(){
            timer=setInterval(()=>{
            //记录索引号
            //active删+增 
            const activeArr=document.querySelectorAll('.active')
            activeArr.forEach((item)=>item.classList.remove('active'))
            if(currentIndex===imgArr.length-1){
                    currentIndex=0
            }
            else currentIndex+=1
            imgArr[currentIndex].classList.add('active')
            nameArr[currentIndex].classList.add('active')
            dots[currentIndex].classList.add('active')

        },1000)
        } 
        startTimer()

        //因为圆点和左右和鼠标会影响轮播的定时器 所以定时器得单独一个函数
        
        //奇怪:只执行了一次 第二次鼠标进入就不生效了---因为重复使用定时器 总有新的定时器开启
        //所以需要一个timer来作为定时器固有的名字 这样每次删的都是同一个定时器 保证最多只有一个定时器
        //鼠标进入
        container.addEventListener('mouseenter',()=>{
            clearInterval(timer)
        })
        //鼠标退出
        container.addEventListener('mouseleave',()=>{
            //继续循环
            startTimer()
        })

        //左右按钮
        //上一页
        left.addEventListener('click',()=>{
            clearInterval(timer)
            document.querySelectorAll('.active').forEach(item=>{
                item.classList.remove('active')
            })

            if(currentIndex!=0){
                currentIndex-=1
            }
            else{
                currentIndex=imgArr.length-1
            }
            // 显示当前图片
            imgArr[currentIndex].classList.add('active')
            nameArr[currentIndex].classList.add('active')
            dots[currentIndex].classList.add('active')

            startTimer()
        })
        right.addEventListener('click',()=>{
            clearInterval(timer)
            document.querySelectorAll('.active').forEach(item=>{
                item.classList.remove('active')
            })

            if(currentIndex!=imgArr.length-1){
                currentIndex+=1
            }
            else{
                currentIndex=0
            }
            // 显示当前图片
            imgArr[currentIndex].classList.add('active')
            nameArr[currentIndex].classList.add('active')
            dots[currentIndex].classList.add('active')

            startTimer()
        })
        //圆点被点击
        dots.forEach((dot,index)=>{
            dot.addEventListener('click',()=>{
                clearInterval(timer)
                document.querySelectorAll('.active').forEach(item=>{
                    item.classList.remove('active')
                })
                currentIndex=index
                imgArr[currentIndex].classList.add('active')
                nameArr[currentIndex].classList.add('active')
                dots[currentIndex].classList.add('active')

                startTimer()
            })
        })

        
        
    </script>
</body>
</html>

2.二级导航

考点:

语法:

css:父子关系

A>B --A下的直属B

A+空格+B--A下所有B(后代)

border:1px solid color

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        ul{
            list-style: none;
        }
        .navigator{
            width: 80%;
            display: flex;
            background-color: dodgerblue;
            justify-content: space-evenly;
        }
        .nav-item{
            position: relative;
            border: 1px solid beige;
            border-bottom: none;
            border-top: none;
            padding: 1%;
        }
        /* 二级菜单的位置要相对.nav-item
            使用position的同时元素是悬浮在上面 */
        /* ul参考.nav-item的位置 */
        .nav-item>ul{
            display: none;
            position: absolute;
            top: 100%;
            left: 0;
            background-color: dodgerblue;

        }
        
        .nav-item>ul>li{
            height: 30px;
            border: 1px solid beige;
            position: relative; /* 三级导航参考二级菜单的位置*/
            line-height: 30px;
        }
        .nav-item:hover>ul{
            display: block;
            width: 100%;
            background-color: dodgerblue;
            text-align: center;
        }
        .nav-item:hover li{
            height:30px;
            border: 1px solid beige;
        }


        /* 三级菜单 */
        .nav-item>ul>li>ul{
            position: absolute;
            top: 0%;
            left: 100%;
            width: 100%;
            background-color: dodgerblue;
            border: 1px solid beige;
            display: flex;
        }
        
        .nav-item ul li:hover >ul {
            display: flex;
        }
        .nav-item>ul>li>ul>li{
            height: 30px;
            border: 1px solid beige;
            line-height: 30px;
            text-align: center;
        }

    </style>
</head>
<body>
    <div class="navigator">
        <div class="nav-item">首页</div>
        <div class="nav-item">学校介绍
            <ul>
                <li>1学习2
                    <ul>
                        <li>三级</li>
                        <li>sanji</li>
                    </ul>
                </li>
                <li>2学校</li>
            </ul>
        </div>
        <div class="nav-item">学生发展
            <ul>
                <li>1学习2</li>
                <li>2学校</li>
            </ul>
        </div>
    </div>
</body>

</html>

3.瀑布流

考点:

语法:

页面加载:

window.οnlοad=函数页面加载就触发

offsetWidth offsetHeight元素总尺寸

clientWidth--盒子宽度(不含边框)

数组.push(元素)

记得js里对于宽高等用 ->数字+'px'

Math.floor()向下取整

Math.random()*某个数 Math.random<=1

`XX${XX}`

监听页面滚动 window.οnscrοll=函数

逻辑:

页面加载时展示数据->页面加载完成后触发瀑布流函数,且页面尺寸变化window.οnresize=waterFall

->瀑布流函数(负责元素布局:容器宽,元素宽,hrr放每列高(一开始6个高),每次都更新高度)

-》新建函数--负责添加新元素(新建的数量,元素内容,元素放到新数组)--一定要返回这个新数组

-》页面滚动的时候触发函数--(document.documentElement.clientHeight是网页高度)如果页面高度大于内容,就开一个倒计时:把之前的新数组每个填到container里面 再用waterfall()控制位置

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .container{
            margin: 0 auto;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }
        .container img{
            width: 200px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="item">
            <img src="./yushi_1.jpeg" alt="">
        </div>
        <div class="item">
            <img src="./yushi_2.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_3.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_4.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_5.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_6.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_7.png" alt="">
        </div>
        <div class="item">
            <img src="./yushi_8.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_9.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_10.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_11.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_12.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_13.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_14.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_15.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_16.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_17.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_18.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_19.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_20.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_21.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_22.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_23.JPG" alt="">
        </div>
        <div class="item">
            <img src="./yushi_24.JPG" alt="">
        </div>
    </div>
</body>
<script>
    //页面加载的时候运行瀑布流函数
    window.load=function(){
        waterFall()
        //window.onresize窗口尺寸变化时执行函数
        window.onresize=waterFall
    }
    //瀑布流函数(一开始的布局)
    function waterFall(){
        const item=document.querySelectorAll('.item')
        const container=document.querySelector('.container')
        //获取各元素的宽 算出container的宽
        let width=item[i].offsetWidth
        let clientWidth=document.documentElement.clientWidth
        let columnCount=6
        container.style.width=width*columnCount+'px'

        //把所有item的高放进hrr
        let hrr=[]
        for(let i=0;i<item.length;i++){
            if(i<columnCount){
                item[i].style.left=width*i+'px'
                item[i].style.top='0px'
                hrr.push(item[i].offsetHeight)
            }
            else{
                //方便后面在最短的那列后面添加新的元素
                //最短那一列 高:Math.min(...hrr) +索引号
                let min=Math.min(...hrr)
                let index=hrr.indexOf(min)
                //由此影响元素位置
                item[i].style.top=min+'px'
                item[i].style.left=index*width+'px'
                //最短那个高要加上现在的元素
                hrr[index]+=item[i].offsetHeight
            }
        }
    }
    //默认加载完毕
    let isLoading=false
    //添加新元素
    function getNewItems(){
        const newItems=[]
        const loadCount=Math.floor(Math.random()*11)+20

        for(let i=0;i<loadCount;i++){
            const itemDiv=document.createElement('div')
            itemDiv.className='item'
            const num=(i%24)+1

            let suffix='JPG'
            if(num>1&&num<=9)suffix='PNG'
            else if(num==1)suffix='JPEG'

            const img=document.createElement('img')
            img.src=`yushi_${num}.${suffix}`
            itemDiv.appendChild(img)
            newItems.push(itemDiv)
        }
        return newItems
    }
    

    window.onscroll=function(){
        let container=document.querySelector('.container')
        let containerHeight=container.offsetHeight
        let containerTop=container.offsetTop

        let clientHeight=document.documentElement.clientHeight
        if(containerHeight+containerTop-clientHeight<=0&&!isLoading){
            isLoading=true
            setTimeout(function(){
                let newItems=getNewItems()
                let container=document.querySelector('.container')
                newItems.forEach(item=>{container.appendChild(item)})
                waterFall()
                isLoading=false
            },1000)
        }
    }
</script>
</html>

4.随机点名

考点:

拼接字符串

逻辑:

函数(添加数据),

滚动函数(active删增)

开始/结束按钮绑定事件 start.addEventListener('click',()=>{})

dom获取元素

设置全局变量

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .container{
            width: 50%;
            height: 30%;
            margin: 0 auto;
        }
        .item{
            width: 100%;
            font-size: 20px;
            display: none;
        }
        .active{
            display: block;
        }
        button{
            width: 100px;
            height: 70px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="showArea">
            <!-- 添加50个
            <div class="item">
                <span></span>
                <span></span>
            </div> -->
        </div>
        <div class="control">
            <button class="start">开始</button>
            <button class="end">结束</button>
        </div>
    </div>
    <script>
        const showArea=document.querySelector('.showArea')
        let data=[]
        //添加 渲染数据
        const add=function(){
            for(let i=0;i<50;i++){
                const item=document.createElement('div')
                item.className='item'
                for(let j=0;j<2;j++){
                    const spanELe=document.createElement('span')
                    if(j===0){
                        if(i<10) spanELe.textContent=`2521070${i}`
                        else spanELe.textContent=`252107${i}`
                    }
                    else spanELe.textContent=`学生${i}`
                    item.appendChild(spanELe)

                }
                showArea.appendChild(item)
                data.push(item)
            }
            return showArea
        }
        const array=add()
        //点击事件
        const start=document.querySelector('.start')
        const end=document.querySelector('.end')
        let currentIndex=0
        let timer=null
        data[0].classList.add('active')

        function roll(){
            const active=document.querySelector('.active')
            active.classList.remove('active')
            currentIndex++
            if(currentIndex>=data.length){
                currentIndex=0
            }
            data[currentIndex].classList.add('active')
        }
        

        start.addEventListener('click',()=>{
            clearInterval(timer)
            timer=setInterval(roll,15)
        })

        end.addEventListener('click',()=>{
            clearInterval(timer)
        })
    </script>
</body>
</html>

5.时钟

考点:

逻辑:获取当下时间+补0函数+每隔1s就更新----一开始就调用函数,后来每隔1s调用一次

语法:

new Date()---从年到每一秒的数据 ---属性:getHours()/getDate()/getDay()

拼接字符串const dateStr=`{year}年{month}月{day}日{week}`

把字符串放到某个元素的内容 XX.textContent=String

setInterval(函数,时间

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="clock">
        <div id="time">00:00:00</div>
        <div class="date" id="date">2026年1月1日</div>
    </div>
    <script>
        function addZero(n){
            return n<10?`0${n}`:n
        }
        function updateClock(){
            const now=new Date()
            const hour=addZero(now.getHours())
            const min=addZero(now.getMinutes())
            const sec=addZero(now.getSeconds())

            const timeStr=`${hour}:${min}:${sec}`
            const weekArr=['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
            const year=now.getFullYear()
            const month=addZero(now.getMonth()+1)
            const day=addZero(now.getDate())
            const week=weekArr[now.getDay()]

            const dateStr=`${year}年${month}月${day}日`

            //渲染
            document.getElementById('time').textContent=timeStr
            document.getElementById('date').textContent=dateStr

        }
        updateClock()
        setInterval(updateClock,1000)
    </script>
</body>
</html>

)

6.弹幕练习

考点:

逻辑:发送函数(检查是否有内容,最后清空input.value)+弹幕移动函数(位置变化)+按钮绑定点击事件实现函数使用

语法:

判断内容input.value.trim()

字符串转数字(XXpx->XX)parseInt(字符串)

弹幕属性:位置 大小 颜色 不换行

判断元素位置是否依旧超过某个容器:

if(rightNum-textWidth-sumWidth>0){

clearInterval(timer)

text.remove()

}

7.放大镜

逻辑:

鼠标mousemove->了解鼠标位置->黄色框框位置->放大图的背景图片位置

语法:

XX.getBoundingClientRect()----获取XX元素所有的位置信息

注意鼠标左移相当于放大图的背景向右移

background-image: url(./yushi_1.jpeg);

background-repeat: no-repeat;

background-size: cover;

border:1px solid black;

display: inline-block;

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .con{
            width: 100%;
            height: 1000px;
        }
        .small{
            width: 400px;
            height: 400px;
            background-image: url(./yushi_1.jpeg);
            background-repeat: no-repeat;
            background-size: cover;
            border:1px solid black;
            display: inline-block;
            position: relative;
        }
        .black{
            width: 100px;
            height: 100px;
            border: 1px solid yellow;
            position: absolute;
            pointer-events: none;
        }
        .big{
            width: 400px;
            height: 400px;
            background-image: url(./yushi_1.jpeg);
            background-repeat: no-repeat;
            background-size: 960px,960px;
            border:1px solid black;
            display: inline-block;
            background-position: 0,0;
        }
    </style>
</head>
<body>
    <div class="con">
        <div class="small">
            <div class="black"></div>
        </div>
        <div class="big">
        </div>
    </div>
    <script>
        const small=document.querySelector('.small')
        const big=document.querySelector('.big')
        const black=document.querySelector('.black')
        //鼠标进入small 每次都获取位置
        small.addEventListener('mousemove',(e)=>{
            //获取small元素的所有位置信息
            const rect=small.getBoundingClientRect()
            //e.clientX--相对浏览器的水平位置--从浏览器最左边 → 鼠标位置
            //rect.left--元素相对浏览器的水平位置--small 盒子左边距离浏览器最左边的距离
            //相减得鼠标相对盒子里的位置
            const x=e.clientX-rect.left
            const y=e.clientY-rect.top

            black.style.left=x-(parseInt(black.offsetWidth)/2)+'px'
            black.style.top=y-(parseInt(black.offsetHeight)/2)+'px'
        
        
            //如果鼠标在盒中
            if(x>=0&&x<=rect.width&&y>=0&&y<=rect.height){
                //backgroundPositionX/Y指的是图片怎么移动
                //鼠标向左,放大图的图相当于向右(画框固定 画移动)
                big.style.backgroundPositionX=-x*2.4+'px'
                big.style.backgroundPositionY=-y*2.4+'px'
            }
        
        })

    </script>
</body>
</html>

8.tab栏

考点:

active删与增

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .navigator{
            display: flex;
            font-size: 25px;
            color: grey;
            gap: 100px;
        }
        .name{
            cursor: pointer;
        }
        .content{
            font-size: 20px;
            position: relative;
        }
        .text{
            width: 100px;
            height: 100px;
            display: none;
            position: absolute;
            left: 0;
            top: 100%;
        }
        .active{
            display: block;
        }
        .navigator .active{
            color: green;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="navigator">
            <div class="name active">英雄联盟</div>
            <div class="name">DOTA</div>
            <div class="name">风暴英雄</div>
        </div>
        <div class="content">
            <div class="text active">123</div>
            <div class="text">456</div>
            <div class="text">789</div>
        </div>
    </div>
    <script>
        const textSum=document.querySelectorAll('.text')
        const nameSum=document.querySelectorAll('.name')

        for(let i=0;i<nameSum.length;i++){
            nameSum[i].addEventListener('click',()=>{
                const active=document.querySelectorAll('.active')
                active.forEach((item)=>{
                    item.classList.remove('active')
                })
                textSum[i].classList.add('active')
                nameSum[i].classList.add('active')
            })
        }
    </script>
</body>
</html>

9.页面回到顶部

考点

窗口绑定滚动事件(滚动就触发函数--按钮存不存在)+点击按钮后window.screenY逐渐减小

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .exp{
            height: 200px;
        }
    </style>
</head>
<body>
    <div>
        <div class="exp">1</div>
        <div class="exp">2</div>
        <div class="exp">3</div>
        <div class="exp">4</div>
        <div class="exp">5</div>
        <div class="exp">6</div>
        <div class="exp">7</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp">8</div>
        <div class="exp exp_bottom" >9</div>
    </div>
    <button id="backTop">回到顶部</button>
</body>
<script>
    const backTop=document.querySelector('#backTop')
    window.addEventListener('scroll',function(){
        const n=document.documentElement.scrollTop
        backTop.style.opacity=window.scrollY===0?0:1
    })
    function smoothScrollTop(){
        let currentY=window.screenY
        if(currentY>0){
            let step=Math.floor(currentY/10)
            step=Math.max(step,5)
            window.scrollTo(0,currentY-step)
            setTimeout(smoothScrollTop,15)
        }

    }
    backTop.addEventListener('click',smoothScrollTop)
</script>
</html>

10.动态表格

渲染函数+重置+添加

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
         body{
            font-size: 18px;
        }
        .add-btn{
            margin: 0 auto;
            background-color: green;
            width: 200px;
            display: flex;
            /* align-items: center; */
            justify-content: center;
            font-size: 20px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            text-align: center;
            margin: 50 auto 20px;
        }
        th,td{
            border: 1px solid #ccc;
            padding: 10px;
        }
        th{
            background-color: lightgreen;
            color: white;
        }
        tr.odd{
            color: black;
            background-color: white;
        }
        tr.even{
            color: white;
            background-color: black;
        }
        .modal-container{
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            background-color: rgba(0,0,0,0.5);
            display: none;
            justify-content: center;
            align-self: center;
            z-index: 999;
        }
        .form-box{
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            width: 400px;
            height: 300px;
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }
        .form-box input,.form-box select {
            width: 120px;
            height: 32px;
            padding: 0 8px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 4px;
        }
        /* 4. 表单按钮样式 */
        .form-box button {
            width: 100%;
            padding: 8px;
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            margin-top: 10px;
        }
        .submit-btn {
            width: 240;
            height: 32px;
            background-color: green;
        }
        .cancel-btn {
            width: 240;
            height: 32px;
            background-color: #6c757d;
        }
    </style>
</head>
<body>
    <div>
        <button class="add-btn">添加</button>
    </div>
    <div class="modal-container" id="add-modal">
        <div action="" class="form-box" autocomplete="off">
            学号:
            <input type="text" class="stu-id" name="id" >
            姓名:
            <input type="text" class="uname" name="uname">
            性别:
            <select type="text" class="gender" name="gender">
                <option value="女">女</option>
                <option value="男">男</option>
            </select>
            二级学院:
            <input type="text" class="stu-college">
            班级:  
            <input type="text" class="stu-class">
            专业:<input type="text" id="stu-major">
            辅导员:<input type="text" id="stu-counselor">
            <button class="submit-btn" type="button">提交</button>
            <button class="cancel-btn" type="button">取消</button>
        </div>
    </div>
    <table class="container">
        <thead>
            <tr>
                <th>序号</th>
                <th>学号</th>
                <th>姓名</th>
                <th>性别</th>
                <th>二级学院</th>
                <th>班级</th>
                <th>专业</th>
                <th>辅导员</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody class="student-tbody">
            <!-- <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td> -->
        </tbody>
    </table>
</body>
<script>
    //1.学生数据创造+渲染(结构)函数定义,使用
    //创建一个空数组 放对象
    const studentList=[]
    for(let i=1;i<=50;i++){
        //数组.push(要加的内容)
        studentList.push({
            id:i,
            name:`学生${i}`,
            gender:i%2===1?'女':'男',
            college:`${i}学院`,
            className:`${i}班`,
            major:'计算机',
            counselor:'张老师'
        })
    }
    //渲染函数
    function render(){
        //tbody是整个studentList放的地方
        const tbody=document.querySelector('tbody')
        tbody.innerHTML=''
        //传入数组里每一个元素
        //数组.forEach((当前元素, 索引) => { 循环逻辑 })
        studentList.forEach((student,index)=>{
            //创建tr(表单中的行)
            const tr=document.createElement('tr')
            tr.className=(index+1)%2==1?'odd':'even'
            //能一次性把整行的 HTML 结构赋值给 <tr> 元素
            tr.innerHTML=`
                <td>${index+1}</td>
                <td>${student.id}</td>
                <td>${student.name}</td>
                <td>${student.gender}</td>
                <td>${student.college}</td>
                <td>${student.className}</td>
                <td>${student.major}</td>
                <td>${student.counselor}</td>
                //这个index为后续删除做准备
                <td><button class="delete-btn" data-index="${index}">删除</button></td>
            `
            //将tr加到tbody里面
            tbody.appendChild(tr)
        })
    }
    //运用渲染函数
    render()


    //2.删除+渲染
    //.student-tbody 是「静态元素」,利用「事件冒泡」机制处理子元素事件
    //为什么是给.student-tbody绑定:因为按的是这一行的按钮,删的是这一行的元素
    //绑定到父元素上能避免 "动态元素需要重复绑定事件" 的问题
    document.querySelector('.student-tbody').addEventListener('click',function(e){
        if(e.target.className==='delete-btn'){
            const isConfirm=confirm('确定要删除这一行吗?')
            if(isConfirm){
                //delIndex 拿到的就是按钮上 data-index 的值(比如 0/1/2 等)。
                const delIndex=e.target.dataset.index
                //(从哪里开始删,删多少个)
                studentList.splice(delIndex,1)
                render()
            }
        }
    })


    //3.添加+框内内容清理
    //modal 是弹窗容器 formBox是添加内容的整体 formInput是内容
    const modal=document.getElementById('add-modal')
    const formBox=document.querySelector('.form-box')
    const formInput=document.querySelectorAll('input,select')
    function resetForm(){formInput.forEach(input=>{
        //判断类型 如果是INPUT就清空内容;SELECT就
        if(input.tagName==='INPUT'){
            input.value=''
        }
        //selectedIndex是select里option的索引号
        //重置后都变回 "女";
        else if(input.tagName==='SELECT'){
            input.selectedIndex=0
        }
    })}

    //添加按钮绑定事件
    document.querySelector('.add-btn').addEventListener('click',function(e){
        modal.style.display='flex'
    })
    //删除按钮绑定事件
    document.querySelector('.cancel-btn').addEventListener('click',function(){
        //不展示内容
        modal.style.display='none'
        //清空内容+重新渲染
        resetForm()
    })

    
    document.querySelector('.sumbit-btn').addEventListener('click',function(){
        const id=document.querySelector('.stu-id').value.trim()
        const name=document.querySelector('.uname').value.trim()
        const gender=document.querySelector('.gender').value.trim()
        const college=document.querySelector('.stu-college').value.trim()
        const className=document.querySelector('.stu-class').value.trim()
        const major=document.querySelector('#stu-major').value.trim()
        const counselor=document.querySelector('#stu-counselor').value.trim()

        if(!id||!name || !college || !className || !major || !counselor){
                alert('请填写所有必填信息')
                return
        }

        studentList.push({
            id:id,
            name:name,
            gender: gender,
            college: college,
            className: className,
            major: major,
            counselor: counselor
        })

        modal.style.display='none'
        //重置输入框
        resetForm()
        //渲染
        render()
    })

</script>
</html>

7.正则表达式

  1. 手机号验证

^1[3-9]\d{9}$

  1. 邮箱验证

^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

  1. 身份证号(简单版)

^\d{15}\|\^\\d{17}\[\\dXx\]

  1. 中文

\\u4e00-\\u9fa5

  1. 提取所有数字

\d+

JS获取数据

2. fetch(原生,不用装包)

js

复制代码
fetch('https://api.xxx.com/data')
  .then(res => res.json())
  .then(data => {
    console.log(data)
  })

async/await 写法:

js

复制代码
async function getData() {
  const res = await fetch('https://api.xxx.com/data')
  const data = await res.json()
  console.log(data)
}

3. axios(项目 99% 用这个)

安装

bash

运行

复制代码
npm install axios

GET 获取数据

js

复制代码
import axios from 'axios'

axios.get('https://api.xxx.com/data')
  .then(res => {
    console.log(res.data)
  })

async/await(最常用)

js

复制代码
async function getData() {
  const res = await axios.get('https://api.xxx.com/data')
  console.log(res.data)
}

POST 提交数据

js

复制代码
axios.post('https://api.xxx.com/login', {
  username: 'zs',
  password: '123'
}).then(res => {
  console.log(res.data)
})

二、Vue 里一般怎么写?(实战写法)

在 Vue 组件里获取数据,写在 created 或 onMounted

js

复制代码
export default {
  data() {
    return {
      list: []
    }
  },
  async created() {
    const res = await axios.get('https://api.xxx.com/list')
    this.list = res.data
  }
}

JS里使用方法


在 JavaScript 里怎么用

1. 测试是否匹配(验证)

js

复制代码
const reg = /^1[3-9]\d{9}$/;
console.log(reg.test('13812345678')); // true/false

2. 查找匹配

js

复制代码
const str = 'abc123def456';
const nums = str.match(/\d+/g); // ['123','456']

3. 替换

js

复制代码
const str = 'hello 123 world';
const res = str.replace(/\d/g, '*'); // 'hello *** world'

4. 切分字符串

js

复制代码
const str = 'a,b;c d';
const arr = str.split(/[,; ]/); // ['a','b','c','d']

二.Vue考点

一、文件 1:src/App.vue(根组件,核心考点全覆盖)

1. 模板部分 <template>

vue

复制代码
<template>
  <div>
    <h1>{{ msg }}</h1>
    <p>计算属性:{{ fullName }}</p>
    <button @click="add">+1</button>
    <button @click="toggle">切换显示</button>

    <!-- v-if vs v-show 高频考点 -->
    <div v-if="isShow">v-if 会销毁/重建DOM</div>
    <div v-show="isShow">v-show 仅切换display:none</div>

    <!-- v-for 必须加key 高频考点 -->
    <ul>
      <li v-for="item in list" :key="item.id">{{ item.name }}</li>
    </ul>

    <!-- 父子组件通信:父传子用props -->
    <Child :msg="parentMsg" @get-child="handleChild" />

    <!-- keep-alive 缓存组件 高频考点 -->
    <keep-alive>
      <router-view />
    </keep-alive>
  </div>
</template>

表格

语法 作用 考试考点
{``{ msg }} 插值语法,把响应式数据渲染到页面 Vue 模板语法基础
@click="add" v-on:click 简写,绑定点击事件 事件绑定,@ 是语法糖
v-if="isShow" 条件渲染,条件为 false 时销毁 DOM v-show的区别:v-if开销大,适合不频繁切换
v-show="isShow" 条件渲染,条件为 false 时仅隐藏 DOM v-if的区别:v-show开销小,适合频繁切换
v-for="item in list" 列表渲染,遍历数组渲染列表 必须加:key,用于 Diff 算法复用 DOM,提升性能
:key="item.id" v-bind:key 简写,绑定唯一标识 禁止用index作为 key,避免列表顺序错乱
:msg="parentMsg" v-bind:msg 简写,父组件向子组件传值 父→子通信核心语法
@get-child="handleChild" 监听子组件触发的get-child事件 子→父通信核心语法
<keep-alive> 缓存包裹的组件,避免重复创建销毁 配合router-view缓存页面,触发activated/deactivated钩子
<router-view /> 路由出口,渲染匹配到的路由组件 Vue Router 核心,单页应用的页面容器

子传父


2. 脚本部分 <script setup>

vue

复制代码
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import Child from './components/Child.vue'

// 1. 响应式数据 高频考点
const msg = ref('Vue考试必背')
const count = ref(0)
const isShow = ref(true)
const parentMsg = ref('我是父组件')
const list = ref([{id:1,name:'张三'},{id:2,name:'李四'}])

// 2. 计算属性 computed 高频考点
const fullName = computed(()=>{
  return msg.value + '🔥'
})

// 3. 侦听器 watch 高频考点
watch(count,(newVal, oldVal)=>{
  console.log('count变了', newVal, oldVal)
})

// 4. 生命周期钩子 onMounted 高频考点
onMounted(()=>{
  console.log('组件挂载完成,适合发网络请求')
})

// 5. 方法定义
const add = ()=>{ count.value++ }
const toggle = ()=>{ isShow.value = !isShow.value }

// 6. 子传父事件处理
const handleChild = (val)=>{
  console.log('子组件传过来的数据:', val)
}

// 7. nextTick 高频考点
const testNextTick = async ()=>{
  await nextTick()
  console.log('DOM已完成更新,可获取最新DOM')
}
</script>

表格

语法 作用 考试考点
ref() 创建基本类型的响应式数据,访问 / 修改需用.value Vue3 响应式基础,ref用于基本类型,reactive用于对象
computed() 计算属性,有缓存,依赖数据变化时才重新计算 methods的区别:computed有缓存,methods每次渲染都执行
watch() 侦听器,监听响应式数据的变化,触发回调 适合异步 / 开销大的操作,可监听单个 / 多个数据
onMounted() 生命周期钩子,组件挂载到 DOM 后执行 发送网络请求、初始化 DOM 操作的最佳位置
nextTick() 等待 DOM 更新完成后执行回调 解决数据更新后 DOM 未同步的问题,获取最新 DOM
defineProps() 子组件接收父组件传的 props(在 Child.vue 中) 父→子通信核心,props是只读的,不可直接修改
defineEmits() 子组件定义可触发的事件(在 Child.vue 中) 子→父通信核心,通过emit()触发事件传值

3. 样式部分 <style scoped>

vue

复制代码
<style scoped>
/* scoped 表示样式仅作用于当前组件,不会污染全局 */
</style>

表格

语法 作用 考试考点
scoped 样式隔离,仅当前组件生效 Vue 组件样式封装,避免全局样式冲突

二、文件 2:src/components/Child.vue(子组件,父子通信考点)

vue

复制代码
<template>
  <div>
    <p>子组件接收父组件数据:{{ msg }}</p>
    <button @click="sendToParent">点我传值给父组件</button>
  </div>
</template>

<script setup>
// 1. 父传子:defineProps 接收props
const props = defineProps({
  msg: String // 声明接收的props类型
})

// 2. 子传父:defineEmits 定义事件
const emit = defineEmits(['get-child'])

// 3. 触发事件,向父组件传值
const sendToParent = ()=>{
  emit('get-child', '我是子组件的数据')
}
</script>

表格

语法 作用 考试考点
defineProps() 声明子组件可接收的父组件传值 父→子通信唯一合法方式,props只读
defineEmits() 声明子组件可触发的事件 子→父通信唯一合法方式,通过emit()传值
emit('事件名', 数据) 触发自定义事件,向父组件传值 子组件主动向父组件通信的核心语法

三、文件 3:src/router/index.js(路由,高频考点)

js

复制代码
import { createRouter, createWebHistory } from 'vue-router'

// 1. 路由懒加载 高频考点
const routes = [
  {
    path: '/', // 路由路径
    name: 'home', // 路由名称(可选)
    component: () => import('../views/Home.vue') // 懒加载组件
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/About.vue')
  }
]

// 2. 创建路由实例
const router = createRouter({
  // history模式 高频考点:无#,需要后端配置
  history: createWebHistory(import.meta.env.BASE_URL),
  routes // 路由规则
})

// 3. 全局前置路由守卫 高频考点(登录拦截)
router.beforeEach((to, from, next) => {
  console.log('路由跳转前触发', to.path, from.path)
  next() // 必须调用next()才能继续跳转
})

export default router

表格

语法 作用 考试考点
createWebHistory() 开启history路由模式,URL 无# hash模式的区别:hash兼容性好,history需后端配置
() => import() 路由懒加载,按需加载组件 优化首屏加载速度,减少初始包体积
router.beforeEach() 全局前置路由守卫 做登录权限拦截,所有路由跳转前都会触发
next() 路由守卫的放行方法 必须调用,否则路由会被拦截

四、文件 4:src/stores/counter.js(Pinia,状态管理考点)

js

复制代码
import { defineStore } from 'pinia'

// 定义Store,第一个参数是唯一id
export const useCounterStore = defineStore('counter', {
  // 1. state:存储全局状态
  state: () => ({
    num: 0
  }),
  // 2. getters:计算属性,类似computed,有缓存
  getters: {
    doubleNum: (state) => state.num * 2
  },
  // 3. actions:修改state的方法,支持异步
  actions: {
    addNum() {
      this.num++ // 直接修改state,无需mutation
    }
  }
})

表格

语法 作用 考试考点
defineStore() 定义 Pinia 的 Store Pinia 核心 API,替代 Vuex
state 存储全局响应式状态 全局共享数据的容器
getters 计算属性,基于 state 派生,有缓存 类似组件的computed
actions 修改 state 的方法,支持异步操作 替代 Vuex 的mutation+action,直接修改 state

五、文件 5:src/main.js(项目入口,全局配置)

js

复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'

// 1. 创建Vue应用实例
const app = createApp(App)

// 2. 注册Pinia和路由插件
app.use(createPinia())
app.use(router)

// 3. 挂载到DOM
app.mount('#app')

表格

语法 作用 考试考点
createApp(App) 创建 Vue 应用实例 Vue3 应用入口,替代 Vue2 的new Vue()
app.use() 注册全局插件(Pinia、Router 等) 全局配置的核心方法
app.mount('#app') 把 Vue 应用挂载到index.html#app元素 应用启动的最后一步

六、文件 6:src/views/Home.vue / About.vue(页面组件)

Home.vue为例,About.vue结构完全一致:

vue

复制代码
<template>
  <div class="home">
    <h1>首页</h1>
    <p>这是路由匹配到的页面组件</p>
    <button @click="goToAbout">跳转到About页</button>
  </div>
</template>

<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()

// 编程式导航 高频考点
const goToAbout = () => {
  router.push('/about')
}
</script>

<style scoped>
.home {
  padding: 20px;
}
</style>

表格

语法 作用 考试考点
useRouter() 获取路由实例 编程式导航的核心 API
router.push() 编程式导航,跳转到指定路由 替代<router-link>,适合 JS 逻辑中跳转

🚀 完整网页打开步骤(照着做 100% 成功)

步骤 1:确保所有文件都正确创建

你需要在项目中创建这些文件,结构如下:

plaintext

复制代码
vue-project/
├── src/
│   ├── components/
│   │   └── Child.vue  ✅ 已粘贴
│   ├── stores/
│   │   └── counter.js ✅ 已粘贴
│   ├── views/
│   │   ├── Home.vue   ✅ 已创建
│   │   └── About.vue  ✅ 已创建
│   ├── router/
│   │   └── index.js   ✅ 已粘贴
│   ├── App.vue        ✅ 已粘贴
│   └── main.js        ✅ 已粘贴
└── ...

步骤 2:启动开发服务器

  1. 打开 VS Code 终端(或 CMD),确保在vue-project目录下

  2. 执行启动命令: bash

    运行

    复制代码
    npm run dev
  3. 等待终端输出: plaintext

    复制代码
    VITE v8.0.3  ready in XXXX ms
    → Local: http://localhost:5173/

步骤 3:打开网页

  1. 直接点击终端里的http://localhost:5173/,或复制到浏览器地址栏
  2. 回车即可打开你的 Vue 项目网页,效果如下:
    • 显示根组件的内容(You did it!、按钮、列表等)
    • 点击+1按钮,数字会增加
    • 点击切换显示v-if/v-show的元素会隐藏 / 显示
    • 点击子组件的按钮,控制台会打印子组件传的值
    • 点击首页的跳转到About页,会路由跳转到 About 页面

步骤 4:停止 / 重启服务器

  • 停止:在终端按Ctrl + C
  • 重启:重新执行npm run dev

🎯 明天考试必背核心结论(直接默写)

  1. 响应式原理 :Vue3 用Proxy,Vue2 用Object.defineProperty
  2. v-if vs v-showv-if销毁 DOM,v-show仅隐藏;v-if适合不频繁切换,v-show适合频繁切换
  3. computed vs watch vs methodscomputed有缓存,watch监听变化,methods每次渲染都执行
  4. 父子通信 :父→子用props,子→父用$emit(Vue3 用defineEmits
  5. 路由模式hash#,兼容性好;history#,需后端配置
  6. Pinia 核心state存数据,actions改数据,无mutation
  7. nextTick 作用:DOM 更新后执行回调,获取最新 DOM
  8. key 的作用 :Diff 算法复用 DOM,提升性能,禁止用index作为 key
  9. 生命周期onMounted发请求,beforeUnmount做清理
  10. 路由懒加载() => import(),优化首屏加载速度

新建vue项目

打开终端(cmd / PowerShell / VS Code 终端)

bash

运行

复制代码
node -v
npm -v

只要有版本号就行,没有就去装:https://nodejs.org/LTS 版


2. 创建 Vue 项目(官方推荐方式)

① 进入你想放项目的文件夹

bash

运行

复制代码
cd 你的文件夹路径

② 执行创建命令

bash

运行

复制代码
npm create vue@latest

③ 一路按回车(默认即可)

必选:RouterPinia(学 Vue 路由和状态管理必备)

会问你这些,直接回车默认:

  • Project name: 项目名(不改直接回车)
  • TypeScript: No
  • JSX: No
  • Vue Router: Yes(建议要)
  • Pinia: Yes(建议要)
  • ESLint: Yes
  • Prettier: Yes

3. 进入项目 & 安装依赖

已生成代码

bash

运行

复制代码
cd 你的项目名
npm install

4. 启动项目

bash

运行

复制代码
npm run dev

出现类似这样就是成功了:

plaintext

复制代码
  Local:   http://localhost:5173/

浏览器打开这个地址就能看到 Vue 页面。

相关推荐
前端极客探险家8 小时前
React 全面入门与进阶实战教程
前端·javascript·react.js
wjs20248 小时前
SQL SELECT DISTINCT 详解
开发语言
计算机安禾9 小时前
【数据结构与算法】第25篇:静态查找(一):顺序查找与折半查找
java·开发语言·数据结构·学习·算法·visual studio code·visual studio
cch89189 小时前
易语言与Java对比:中文编程VS跨平台王者
java·开发语言
cookies_s_s9 小时前
C++ 模板与泛型编程
linux·服务器·开发语言·c++
minji...9 小时前
Linux 多线程(一)线程概念,轻量级进程,执行流,线程创建
java·开发语言·jvm
cch89189 小时前
易语言 vs Go:初学者与专业开发之选
开发语言·后端·golang
0xDevNull9 小时前
Java 17 新特性概览与实战教程
java·开发语言·后端
java1234_小锋9 小时前
Python高频面试题:python里面模块和包之间有什么区别?
开发语言·python