JavaScript—— 常见网页特效

JavaScript—— 常见网页特效JavaScript 常见网页特效


一、常见网页特效

1. 案例:网页轮播图

  1. 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
  2. 点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。
  3. 图片播放的同时,下面小圆圈模块跟随一起变化。
  4. 点击小圆圈,可以播放相应图片。
  5. 鼠标不经过轮播图,轮播图也会自动播放图片。
  6. 鼠标经过,轮播图模块,自动播放停止。

1.1 案例分析

1.1.1 左右按钮的显示与隐藏

请添加图片描述
在这里插入图片描述

// 等页面所有元素加载完后再执行js window.addEventListener('load', function () { 
     //this.alert('1'); // 测试 // 1. 获取元素 var arrow_l = this.document.querySelector('.arrow-l'); var arrow_r = this.document.querySelector('.arrow-r'); var focus = document.querySelector('.focus'); // 2. 鼠标经过focus 就显示隐藏的左右按钮 focus.addEventListener('mouseenter', function () { 
     arrow_l.style.display = 'block'; arrow_r.style.display = 'block'; }) // 鼠标离开focus 就隐藏左右按钮 focus.addEventListener('mouseleave', function () { 
     arrow_l.style.display = 'none'; arrow_r.style.display = 'none'; }) }) 

请添加图片描述

1.1.2 动态生成小圆圈

请添加图片描述

// 3. 动态生成小圆圈,有几张图片我们就生成几个小圆圈 var ul = focus.querySelector('ul'); var ol = focus.querySelector('.circle'); // console.log(ul.children.length); test for (var i = 0; i < ul.children.length; i++) { 
     // 创建一个小li var li = this.document.createElement('li'); // 把小li插入到ol里面 ol.appendChild(li); } // 把ol的第一个小li设置类名为 current ol.children[0].className = 'current'; 

在这里插入图片描述

1.1.3 小圆圈的排他思想

请添加图片描述
排他思想的口诀: 干掉所有人,留下我自己

// 4. 小圆圈的排他思想 我们可以直接生成小圆圈的同时直接绑定点击事件 li.addEventListener('click', function () { 
     // 干掉所有人 把所有的小li 清除 current 类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ' '; } // 留下我自己 当前的小li 设置current 类名 this.className = 'current'; }) 

把这段代码写到上一段代码的for循环里面

1.1.4 点击小圆圈滚动图片

请添加图片描述

html
在这里插入图片描述
css
在这里插入图片描述
js








for (var i = 0; i < ul.children.length; i++) { 
     // 创建一个小li var li = this.document.createElement('li'); //记录当前小圆圈的索引号 通过自定义属性来做 li.setAttribute('index', i); // 把小li插入到ol里面 ol.appendChild(li); // 4. 小圆圈的排他思想 我们可以直接生成小圆圈的同时直接绑定点击事件 li.addEventListener('click', function () { 
     // 干掉所有人 把所有的小li 清除 current 类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ' '; } // 留下我自己 当前的小li 设置current 类名 this.className = 'current'; // 5. 点击小圆圈,移动图片 当然移动的是 ul // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是往左走,所以是负值 // 当我们点击了某个小li 就拿到当前小li 的索引号 var index = this.getAttribute('index'); //console.log(index); test var focusWidth = focus.offsetWidth; //console.log(focusWidth); test animate(ul, -index * focusWidth); }) } 

请添加图片描述

1.1.5 点击右侧按钮一次,就让图片滚动一张

请添加图片描述
将href的值 “#” 改写成 “javascript:;” ,使其被点击后不会跳到页面最顶端
在这里插入图片描述
将之前在for循环内部定义的focusWidth提到外面去定义,这样在外面也可以使用了。
在这里插入图片描述
将第一张的图片复制一份放到最后面
在这里插入图片描述












// 6. 点击右侧按钮一次,就让图片滚动一张 var num = 0; arrow_r.addEventListener('click', function () { 
     // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == ul.children.length - 1) { 
     ul.style.left = 0; num = 0; } num++; animate(ul, -num * focusWidth); }) 

请添加图片描述

1.1.6 克隆第一张图片

// 6. 克隆第一张图片(li)放到ul 最后面 var first = ul.children[0].cloneNode(true); ul.appendChild(first); 

1.1.7 点击右侧按钮,小圆圈跟随变化

请添加图片描述

// 7. 点击右侧按钮一次,就让图片滚动一张 var num = 0; // circle 控制小圆圈的播放 var circle = 0; arrow_r.addEventListener('click', function () { 
     // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == ul.children.length - 1) { 
     ul.style.left = 0; num = 0; } num++; animate(ul, -num * focusWidth); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原为0 if (circle == ol.children.length) { 
     circle = 0; } // 先清除其余小圆圈的current类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ''; } // 留下当前的小圆圈的current类名 ol.children[circle].className = 'current'; }) 

请添加图片描述

小bug

1.当我们点击第三个小圆圈会显示第3张图片,然后点击右侧按钮,图片却显示第2张。这是因为我们播放下一张是由num控制的,而num这一个变量和之前做的点击小圆圈事件没有任何关系,所以它们就出现差异。

// 4. 小圆圈的排他思想 我们可以直接生成小圆圈的同时直接绑定点击事件 li.addEventListener('click', function () { 
     // 干掉所有人 把所有的小li 清除 current 类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ' '; } // 留下我自己 当前的小li 设置current 类名 this.className = 'current'; // 5. 点击小圆圈,移动图片 当然移动的是 ul // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是往左走,所以是负值 // 当我们点击了某个小li 就拿到当前小li 的索引号 var index = this.getAttribute('index'); //console.log(index); test //当我们点击了某个小li 就要把这个小li 的索引号给 num num = index; //当我们点击了某个小li 就要把这个小li 的索引号给 circle circle是控制小圆圈自动播放 circle = index; animate(ul, -index * focusWidth); }) 

请添加图片描述

1.1.8 左侧按钮功能实现

// 7. 点击右侧按钮一次,就让图片滚动一张 var num = 0; // circle 控制小圆圈的播放 var circle = 0; arrow_r.addEventListener('click', function () { 
     // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == ul.children.length - 1) { 
     ul.style.left = 0; num = 0; } num++; animate(ul, -num * focusWidth); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原为0 // if (circle == ol.children.length) { 
     // circle = 0; // } // 代码优化 三元表达式 circle = circle == ol.children.length ? 0 : circle; // 调用函数 circleChange(); }) // 9. 左侧按钮做法 arrow_l.addEventListener('click', function () { 
     // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == 0) { 
     num = ul.children.length - 1; // ul向左走为负值 ul.style.left = -num * focusWidth + 'px'; } num--; animate(ul, -num * focusWidth); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle--; // // 如果circle < 0 说明第一张图片 则小圆圈要改为第4个小圆圈 // if (circle < 0) { 
     // circle = ol.children.length - 1; // } // 代码优化 三元表达式 circle = circle < 0 ? ol.children.length - 1 : circle; // 调用函数 circleChange(); }) // 优化 左右按钮的小圆圈排他思想代码一样 就封装为一个函数,调用函数 减少代码重复量 function circleChange() { 
     // 先清除其余小圆圈的current类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ''; } // 留下当前的小圆圈的current类名 ol.children[circle].className = 'current'; } 

请添加图片描述

1.1.9 自动播放功能

请添加图片描述

// 10. 自动播放轮播图 var timer = setInterval(function () { 
     // 手动调用点击事件 arrow_r.click(); }, 2000); 

1.2 节流阀

请添加图片描述

// flag 节流阀 var flag = true; arrow_r.addEventListener('click', function () { 
     if (flag) { 
     flag = false; // 关闭节流阀 // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == ul.children.length - 1) { 
     ul.style.left = 0; num = 0; } num++; animate(ul, -num * focusWidth, function () { 
     flag = true; // 打开节流阀 }); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原为0 // if (circle == ol.children.length) { 
     // circle = 0; // } // 代码优化 三元表达式 circle = circle == ol.children.length ? 0 : circle; // 调用函数 circleChange(); } }) 

请添加图片描述

1.3 代码展示

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> <link rel="stylesheet" href="index.css">  
       <script src="js/animate.js"> 
        script> <script src="js/index.js"> 
         script>  
          head> <body> <div class="focus">  
          <a href="javascript:;" class="arrow-l">< 
           a>  
           <a href="javascript:;" class="arrow-r">> 
            a>  
            <ul> <li> <a href="#"><img src="../images/focus.jpg" alt=""> 
             a>  
              li> <li> <a href="#"><img src="../images/focus1.jpg" alt=""> 
               a>  
                li> <li> <a href="#"><img src="../images/focus2.jpg" alt=""> 
                 a>  
                  li> <li> <a href="#"><img src="../images/focus3.jpg" alt=""> 
                   a>  
                    li>  
                     ul>  
                     <ol class="circle">  
                      ol>  
                       div>  
                        body>  
                         html> 

css

* { 
     margin: 0; padding: 0; } li { 
     list-style: none; } a { 
     text-decoration: none; } .focus { 
     position: relative; width: 721px; height: 455px; background-color: pink; margin: 100px auto; overflow: hidden; } .focus ul { 
     position: absolute; top: 0; left: 0; /* 使轮播图的使用图片都放到一行上去就需要扩大父盒子的宽度 */ width: 600%; } .focus ul li { 
     float: left; } .arrow-l, .arrow-r { 
     display: none; position: absolute; top: 50%; margin-top: -20px; width: 24px; height: 40px; background: rgba(0, 0, 0, .3); text-align: center; line-height: 40px; color: #fff; font-size: 18px; z-index: 2; } .arrow-r { 
     right: 0; } .circle { 
     position: absolute; bottom: 10px; left: 50px; } .circle li { 
     float: left; width: 8px; height: 8px; border: 2px solid rgba(255, 255, 255, 0.5); margin: 0 3px; border-radius: 50%; /*鼠标经过显示小手*/ cursor: pointer; } .current { 
     background: #fff; } 

js

// 等页面所有元素加载完后再执行js window.addEventListener('load', function () { 
     //this.alert('1'); // 测试 // 1. 获取元素 var arrow_l = this.document.querySelector('.arrow-l'); var arrow_r = this.document.querySelector('.arrow-r'); var focus = document.querySelector('.focus'); var focusWidth = focus.offsetWidth; //console.log(focusWidth); test // 2. 鼠标经过focus 就显示隐藏的左右按钮 focus.addEventListener('mouseenter', function () { 
     arrow_l.style.display = 'block'; arrow_r.style.display = 'block'; clearInterval(timer); timer = null; // 清除定时器变量 }) // 鼠标离开focus 就隐藏左右按钮 focus.addEventListener('mouseleave', function () { 
     arrow_l.style.display = 'none'; arrow_r.style.display = 'none'; timer = setInterval(function () { 
     // 手动调用点击事件 arrow_r.click(); }, 2000); }) // 3. 动态生成小圆圈,有几张图片我们就生成几个小圆圈 var ul = focus.querySelector('ul'); var ol = focus.querySelector('.circle'); // console.log(ul.children.length); test for (var i = 0; i < ul.children.length; i++) { 
     // 创建一个小li var li = this.document.createElement('li'); //记录当前小圆圈的索引号 通过自定义属性来做 li.setAttribute('index', i); // 把小li插入到ol里面 ol.appendChild(li); // 4. 小圆圈的排他思想 我们可以直接生成小圆圈的同时直接绑定点击事件 li.addEventListener('click', function () { 
     // 干掉所有人 把所有的小li 清除 current 类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ' '; } // 留下我自己 当前的小li 设置current 类名 this.className = 'current'; // 5. 点击小圆圈,移动图片 当然移动的是 ul // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是往左走,所以是负值 // 当我们点击了某个小li 就拿到当前小li 的索引号 var index = this.getAttribute('index'); //console.log(index); test //当我们点击了某个小li 就要把这个小li 的索引号给 num num = index; //当我们点击了某个小li 就要把这个小li 的索引号给 circle circle是控制小圆圈自动播放 circle = index; animate(ul, -index * focusWidth); }) } // 把ol的第一个小li设置类名为 current ol.children[0].className = 'current'; // 6. 克隆第一张图片(li)放到ul 最后面 var first = ul.children[0].cloneNode(true); ul.appendChild(first); // 7. 点击右侧按钮一次,就让图片滚动一张 var num = 0; // circle 控制小圆圈的播放 var circle = 0; // flag 节流阀 var flag = true; arrow_r.addEventListener('click', function () { 
     if (flag) { 
     flag = false; // 关闭节流阀 // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == ul.children.length - 1) { 
     ul.style.left = 0; num = 0; } num++; animate(ul, -num * focusWidth, function () { 
     flag = true; // 打开节流阀 }); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原为0 // if (circle == ol.children.length) { 
     // circle = 0; // } // 代码优化 三元表达式 circle = circle == ol.children.length ? 0 : circle; // 调用函数 circleChange(); } }) // 9. 左侧按钮做法 arrow_l.addEventListener('click', function () { 
     if (flag) { 
     flag = false; // alert('1'); test // 如果走到了最后复制的一张图片,此时,我们的ul 要快速复原 left 改为 0 if (num == 0) { 
     num = ul.children.length - 1; // ul向左走为负值 ul.style.left = -num * focusWidth + 'px'; } num--; animate(ul, -num * focusWidth, function () { 
     flag = true; }); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle--; // // 如果circle < 0 说明第一张图片 则小圆圈要改为第4个小圆圈 // if (circle < 0) { 
     // circle = ol.children.length - 1; // } // 代码优化 三元表达式 circle = circle < 0 ? ol.children.length - 1 : circle; // 调用函数 circleChange(); } }) // 优化 左右按钮的小圆圈排他思想代码一样 就封装为一个函数,调用函数 减少代码重复量 function circleChange() { 
     // 先清除其余小圆圈的current类名 for (var i = 0; i < ol.children.length; i++) { 
     ol.children[i].className = ''; } // 留下当前的小圆圈的current类名 ol.children[circle].className = 'current'; } // 10. 自动播放轮播图 var timer = setInterval(function () { 
     // 手动调用点击事件 arrow_r.click(); }, 2000); }) 

animate.js

function animate(obj, target, callback) { 
     // console.log(callback); callback = function() {} 调用的时候 callback() // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function () { 
     // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { 
     // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 // if (callback) { 
     // // 调用函数 // callback(); // } callback && callback(); // 短路运算符 如果callback 为true 就会执行后面的callback() } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } 

2. 案例:返回顶部

请添加图片描述请添加图片描述
在之前 仿淘宝固定侧边栏的案例 中实现

js

// 3. 当我们点击了返回顶部模块,就让窗口滚动的页面的最上方 goBack.addEventListener('click', function () { 
     // alert(1); // 里面的x和y 不跟单位的 直接写数字即可 // window.scroll(0, 0); // 因为是窗口滚动 所以对象是window animate(window, 0); }); // 动画函数 function animate(obj, target, callback) { 
     // console.log(callback); callback = function() {} 调用的时候 callback() // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function () { 
     // 步长值写到定时器的里面 // 把我们步长值改为整数 不要出现小数的问题 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - window.pageYOffset) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (window.pageYOffset == target) { 
     // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 // if (callback) { 
     // // 调用函数 // callback(); // } callback && callback(); // 短路运算符 如果callback 为true 就会执行后面的callback() } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 // obj.style.left = window.pageYOffset + step + 'px'; window.scroll(0, window.pageYOffset + step); }, 15); } 

请添加图片描述

3. 案例:筋斗云

3.1 案例分析

请添加图片描述

3.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> * { 
         margin: 0; padding: 0; } ul { 
         list-style: none; } body { 
         background-color: black; } .c-nav { 
         width: 900px; height: 42px; background: #fff url(images/rss.png) no-repeat right center; margin: 100px auto; border-radius: 5px; position: relative; } .c-nav ul { 
         position: absolute; } .c-nav li { 
         float: left; width: 83px; text-align: center; line-height: 42px; } .c-nav li a { 
         color: #333; text-decoration: none; display: inline-block; height: 42px; } .c-nav li a:hover { 
         color: white; } .cloud { 
         position: absolute; left: 0; top: 0; width: 83px; height: 42px; background: url(images/cloud.gif) no-repeat; }  
        style> <script src="animate.js"> 
         script> <script> window.addEventListener('load', function () { 
           // 1. 获取元素 var cloud = document.querySelector('.cloud'); var c_nav = document.querySelector('.c-nav'); var lis = c_nav.querySelectorAll('li'); // 这个current 做为筋斗云的起始位置 var current = 0; // 2. 给所有的小li绑定事件  for (var i = 0; i < lis.length; i++) { 
           // (1) 鼠标经过把当前小li 的位置做为目标值 lis[i].addEventListener('mouseenter', function () { 
           animate(cloud, this.offsetLeft); }); // (2) 鼠标离开就回到起始的位置  lis[i].addEventListener('mouseleave', function () { 
           animate(cloud, current); }); // (3) 当我们鼠标点击,就把当前位置做为目标值 lis[i].addEventListener('click', function () { 
           current = this.offsetLeft; }); } })  
          script>  
           head> <body> <div class="c-nav"> <span class="cloud"> 
            span> <ul> <li class="current"><a href="">首页新闻 
             a> 
              li> <li><a href="#">师资力量 
               a> 
                li> <li><a href="#">活动策划 
                 a> 
                  li> <li><a href="#">企业文化 
                   a> 
                    li> <li><a href="#">招聘信息 
                     a> 
                      li> <li><a href="#">公司简介 
                       a> 
                        li> <li><a href="#">我是佩奇 
                         a> 
                          li> <li><a href="#">啥是佩奇 
                           a> 
                            li>  
                             ul>  
                              div>  
                               body>  
                                html> 

请添加图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201530.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午9:11
下一篇 2026年3月20日 上午9:12


相关推荐

  • 安卓适配AutoSize详解

    安卓适配AutoSize详解GItHub的官方地址:https://gitee.com/lcb1992/AndroidAutoSize一.项目导入implementation’me.jessyan:autosize:1.2.1’1.1manifest里面进行设置<manifest><application><meta-dataandroid:name=”design_width_in_dp”

    2022年6月6日
    30
  • cJSON 使用详解

    cJSON 使用详解由于c语言中,没有直接的字典,字符串数组等数据结构,所以要借助结构体定义,处理json。如果有对应的数据结构就方便一些,如python中用json.loads(json)就把json字符串转变为内建的数据结构处理起来比较方便。一个重要概念:在cjson中,json对象可以是json,可以是字符串,可以是数字。。。cjson数据结构定义:#d…

    2022年6月15日
    76
  • 文心一言:AI人工智能领域的新标杆

    文心一言:AI人工智能领域的新标杆

    2026年3月12日
    2
  • Java编程基础(1)

    Java编程基础(1)经常遇到规范问题,搞的总是在网页上查找,这里总计一下:1、命名规范问题:(1)类名:首字母要大写(2)方法名:首字母要小写,如果是多个单词,第二个单词首字母可以大写,比如setPeople(3)变量:一般变量都是小写(4)常量:一般全部要大写…

    2022年7月8日
    30
  • spi协议详解_一文看懂财务三张表

    spi协议详解_一文看懂财务三张表文章目录SPI协议简介4线还是3线?4种工作模式多种传输速率SPI协议的基本时序SPI协议的升级版FPGA实现SPI协议SPI和IIC的对比总结SPI协议简介板卡内不同芯片间通讯最常用的三种串行协议:UART、I2C、SPI,之前写过串口协议及其FPGA实现,今天我们来介绍SPI协议,SPI是SerialPerripheralInterface的简称,是由Motorola公司推出的一种高速、全双工的总线协议。与IIC类似,SPI也是采用主从方式工作,主机通常为FPGA、MCU或DSP等可编程控制

    2022年10月15日
    3
  • pycharm报错traceback most_cm3d2报错error

    pycharm报错traceback most_cm3d2报错errorPycharm报错Pythonerror:PermissionError:[Errno13]Permissiondenied:在pycharm中读取csv文件时,出现错误PermissionError:[Errno13]Permissiondenied:。看了大部分博客说是因为文件权限问题,或者文件被手动打开,这两个方法都试了试后,无效。解决问题的方法:配置Python编译器时将ScriptPath的路径写到脚本的具体路径,要包含脚本的文件名。如下图。…

    2022年8月26日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号