【07】 PC端+移动端网页特效-pink老师-2022/03

1. PC 端网页特效

1. 元素偏移量offset系列

可以动态得到该元素的位置(偏移)、大小等:

  • 可以获取元素距离带有定位父元素的位置
  • 获取元素自身的大小(宽度 和 高度)
  • offset系列常用于获取元素位置 (但需要注意是否有带定位的父盒子)
  • 注意:返回的数值不带单位
offset系列属性返回
element.offsetParent该元素带定位的父元素,如果父级都没有定位则返回body,与element.parentNode()亲爸爸还是有区别的
element.offsetTop该元素相对带有定位父元素上方的偏移量
element.offsetLeft该元素相对带有定位父元素左边框的偏移量
element.offsetWidth自身包括padding + border + content的宽度,返回数值不带单位
element.offsetHeight自身包括padding + border + content的高度,返回数值不带单位

offset 与 style 的区别

offsetstyle
得到 任意样式表中的 样式值得到行内样式表中的样式值
返回数值不带单位带单位的字符串
offsetWidth 包含 padding+border+width(盒子大小)style.width 不包含padding+border(内容大小)
offsetWidth等属性是 只读属性style.width 可读写属性
结论:想获取元素大小位置,用offset更合适(读)想更改元素值,需要用style改变(写)

【案例:拖动的模态框(登录框)遮挡层 —— 可以鼠标拖动 】

//仿京东放大镜效果

var preview_img = document.querySelector('.preview_img') //小图片盒子
var mask = preview_img.children[1]  //遮罩层
var big = preview_img.children[2]    //大图片盒子
var bigImage = big.firstElementChild;   //大图片

//(1). 鼠标经过小图片盒子 mask和大图片盒子显示,离开隐藏
preview_img.addEventListener('mouseenter', function () {
    mask.style.display = 'block'
    big.style.display = 'block'
})
preview_img.addEventListener('mouseleave', function () {
    mask.style.display = 'none'
    big.style.display = 'none'
})

//(2)黄色的遮挡层跟随鼠标移动
//应该是把鼠标在小图片盒子的坐标 给mask
preview_img.addEventListener('mousemove', function (e) {
    //(1) 先计算出鼠标在盒子内的坐标  ps: 先看小图片盒子是否有定位
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    //(2) 为了使鼠标在mask中间,-mask 宽高的一半
    var maskX = x - mask.offsetWidth / 2;
    var maskY = y - mask.offsetHeight / 2;
    //(3) mask不能超出小图片盒子 +判断条件解决
    var maskMaxX = this.offsetWidth - mask.offsetWidth;  //移动最大距离=大坐标-小坐标
    var maskMaxY = this.offsetHeight - mask.offsetHeight;//100
    //移动的最小距离和最大距离
    if (maskX <= 0) {
        maskX = 0;
    } else if (maskX >= maskMaxX) {
        maskX = maskMaxX;
    }
    if (maskY <= 0) {
        maskY = 0;
    } else if (maskY >= maskMaxY) {
        maskY = maskMaxY;
    }
    mask.style.left = maskX + 'px';
    mask.style.top = maskY + 'px';

    // (4) 大图片盒子移动距离与mask 成比例 maskX / mask 最大移动距离 = big / big最大移动距离
    var bigMaxX = bigImage.offsetWidth - big.offsetWidth; //300
    var bigMaxY = bigImage.offsetHeight - big.offsetHeight;
    var bigX = maskX / maskMaxX * bigMaxX; //根据比例公式计算
    var bigY = maskY / maskMaxY * bigMaxY;
    bigImage.style.left = -bigX + 'px'; //负值+单位!!
    bigImage.style.top = -bigY + 'px';
})

2. 元素可视区client系列

client 翻译过来就是客户端,使用client相关属性可获取元素可视区的相关信息,动态获得该元素的边框大小、元素大小等;

client常用于检测屏幕宽度:

窗口大小变化触 resize事件,可检测屏幕宽度

window.addEventListener('resize', function(){
	let w = document.documentElement.clientWidth;
	console.log(w);
})
client系列属性返回值
element.clientTop元素上边框大小
element.clientLeft元素左边框大小
element.clientWidth自身包括padding+content宽度,不含border,不含单位
element.clientHeight自身包括padding+content高度,不含border,不含单位

立即执行函数

普通函数 声明调用再执行;立即执行函数不需要调用,立刻自己执行,也可以传递参数,多个立即执行函数需要加分号;隔开

写法:第二个括号可以看做调用函数
立即函数最大的作用就是 独立创建了一个作用域

flexible.js 分析
整个js文件内部就是一个立即执行函数,不需要调用就能立即执行;
同时,由于所有独立局部变量都在该作用域中,并不会与其它引入的js文件发生命名冲突
1. (function (){})()

2. (fucntion(){}())

pageshow事件

当一条会话历史记录被执行的时候将会触发页面显示(pageshow)事件。(这包括了后退/前进按钮操作,同时也会在onload 事件触发后初始化页面时触发),根据该事件对象persisted属性可以判断是否 是 缓存中的页面触发pageshow事件,注意,这个事件是给window添加。

3. 元素滚动scroll系列

scroll系列的相关属性可以动态获得该元素的大小、滚动距离等,当滚动条发生变化会触发滚动事件onscroll

scroll常用于获取滚动距离,监听整个页面的滚动,是给windowdocument添加scroll事件,监听某个元素内部滚动直接给某元素加即可,不包含滚动条

scroll系列属性返回值
element.scrollTop返回被卷去的上侧距离,不带单位,可读写
element.scrollLeft返回被卷去的左侧距离,不带单位,可读写
element.scrollWidth返回内容实际宽度,不带单位(因为实际宽度可能超出限定区域,才能加滚动条,获得scroll事件)
element.scrollHeight返回内容实际高度,不带单位
window.pageYOffset整个页面被卷去的头部)【常用返回头部案例】
window.pageXoffset整个页面被卷去的左部
document.documentElement.scrollTop页面滚动的头部,可读写(老写法)
document.documentElement.scrollLeft页面滚动的左侧,可读写(老写法)
案例: 仿淘宝固定侧边栏
滚动到banner上边沿 侧边栏固定
滚订到main主体区域 侧边栏添加 返回头部 功能

页面被卷去的头部:window.pageYOffset
页面被卷去的左部:window.pageXOffset

var backUp = document.querySelector('.back_top');
var sideBar = document.querySelector('.side_bar');
var banner = document.querySelector('.banner');
var mainBox = document.querySelector('main');
var bannerTop = banner.offsetTop; //被卷到banner位置大小
var mainTop = main.offsetTop;   //被卷到main位置大小

document.addEventListener('scroll', function (e) {  //监听整个页面滚动给 window 或 document 加
if (window.pageYOffset >= mainTop){
   backUp.style.display = 'block';
} else if (window.pageYOffset >= bannerTop && window.pageYOffset <= mainTop) {
    sideBar.style.position = 'fixed';
    sideBar.style.top = '0';
} else {
    backUp.style.display = 'none';
    sideBar.style.position = 'absolute';
    sideBar.style.top = h + 'px';
}})

4. 动画函数封装

核心原理:通过定时器setInterval()不断移动盒子距离

  1. 获得盒子当前的移动距离
  2. 让盒子在当前位置+1个移动距离
  3. 利用定时器不断重复该操作
  4. 加1个结束定时器的条件
  5. 注意:此元素需要定位,才能使用element.stytle.left,而且移动也不会影响其它盒子的摆放
简单动画函数封装:需要2个参数:动画对象 + 结束条件

function animate(obj, target, callback) { //目标对象  目标位置 回调函数(原函数执行完了才会执行)
    var step = (target - obj.offsetLeft) / 10;  //减速运动 但永远到不了终点  定时器永远关不掉
    clearInterval(obj.timer)   //如果点击触发动画 则点击速度越快 动画频率越快 因为开启了太多定时器 需要清除以前的定时器
	//var timer = setInterval(function () {   //不同对象调用需要开辟不同的内存空间 性能优化
    obj.timer = setInterval(function () {   //解决方法:封装为对象方法,给把不同元素记录不同定时器
    if (obj.offsetLeft == target) {  
    	clearInterval(obj.timer)
        callback && callback(); //短路运算 都为真 则有callback传进来才会执行
    } else {
		obj.style.left = obj.offsetLeft + 1 + 'px';}}, 30)}  //匀速动画
        if (step <= 1) {
            obj.style.left = target + 'px';  // 使得缓动动画 条件满足
        } else {
			obj.style.left = obj.offsetLeft + step + 'px';}}, 30)}  //缓动动画 
        }
var div = document.querySelector('div')
animate(div, 500)
  1. 缓动动画:让元素的速度有所变化,最常见的就是让速度慢慢停下来(匀速动画)
    原理:让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
    核心算法:(目标值 - 现在位置)/ 10 作为每次移动的距离步长

​ (但这样其实永远也到不到终点,定时器也无法关闭,需要加判断条件)

  1. 动画函数添加回调函数
    原理:函数A 可以作为 函数B的一个参数,当函数B执行完了,再执行函数A,这个过程就叫做回调

  2. 图片无缝滚动原理:在最后插入第一张图(节点的深拷贝),这样两端切换就不会有过渡问题

    • 从最后一张到第一张,可以正常轮播下一张(下一张就是第一张),再迅速跳回第一张

    • 从第一张到最后一张,可以迅速跳到最后一张(就是第一张),再正常轮播上一张

  3. 节流阀:防止轮播图连续点击造成播放过快

    • 原理:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
    • 设置flag变量(相当于水龙头),先关闭水龙头,利用回调函数当动画执行完毕,再打开true
轮播图 / 焦点图

需求分析:
1. 鼠标经过轮播图 左右按钮显示轮播前后 离开隐藏
2. 鼠标点击 左右按钮 轮播图对应播放
3. 对应图片的 小圆点 index高亮 //小圆点的个数应该动态生成
4. 鼠标放在 小圆点上 对应显示轮播图
5. 自动播放轮播图(类似于右键功能)
6. 鼠标经过轮播图,停止自动播放

图片无缝滚动原理,在最后插入第一张图(节点的深拷贝),这样两端切换就不会有过渡问题
从最后一张到第一张,可以正常轮播下一张(下一张就是第一张),再迅速跳回第一张
从第一张到最后一张,可以迅速跳到最后一张,再正常轮播上一张


window.addEventListener('load', function () {
    var focusBox = document.querySelector('.focus') //有定位的父盒子
    var arrowR = focusBox.children[0]
    var arrowL = focusBox.children[1]
    var imgs = focusBox.children[2]
    var dots = focusBox.children[3]

    var w = focusBox.offsetWidth; //轮播框宽度,也就是移动距离的基数
    console.log(w);
    console.log(focusBox.children);


    // (1) 鼠标经过对应显示左右箭头
    focusBox.onmouseenter = function () {
        arrowL.style.display = 'block'
        arrowR.style.display = 'block'
        clearInterval(timer)
        timer = null;
    }
    focusBox.onmouseleave = function () {
        arrowL.style.display = 'none'
        arrowR.style.display = 'none'
        timer = setInterval(function () {
            arrowR.click();
        }, 2000)
    }

    var len = imgs.children.length; //轮播图的数量
    //小圆点个数对应初始轮播图数量len动态生成
    for (var i = 0; i < len; i++) {
        let dot = document.createElement('li')
        dot.setAttribute('data-index', i)
        // dot.innerHTML = "<a href='JavaScript:;'></a>"
        dots.appendChild(dot)
    }
    dots.firstElementChild.classList.add('current') //默认第一个小圆点当前点
    // (3) 对应滚动到 小圆点位置的图片
    for (var i = 0; i < len; i++) {
        dots.children[i].addEventListener('mouseover', function () {
            for (var i = 0; i < len - 1; i++) {
                dots.children[i].classList.remove('current')
            }
            this.classList.add('current')
            index = this.getAttribute('data-index') //index是全局变量,因为要和左右按钮联动
            animateSlow(imgs, -index * w)
        })
    }


    //(2) 左右箭头切换图像 声明自增变量
    //要克隆第一张图片到最后 实现无缝滚动的原理
    var li = imgs.firstElementChild.cloneNode(true)
    imgs.appendChild(li)
    len = imgs.children.length
    var index = 0; //默认index从0开始
    var dotNum = dots.children.length;
    arrowL.addEventListener('click', function () {
        // 如果走到了第一张,index=0,就快速回到最后一张
        if (index == 0) {
            index = len - 1;
            imgs.style.left = -index * w + 'px';
        }
        index--;
        for (var i = 0; i < dotNum; i++) {
            dots.children[i].classList.remove('current')
        }
        dots.children[index % dotNum].classList.add('current')
        animateSlow(imgs, -index * w)
    })
    arrowR.addEventListener('click', function () {
        //如果走到了最后一张图 index=5,就快速回到起点,
        if (index == len - 1) {
            index = 0;
            imgs.style.left = -index * w
        }
        index++;
        for (var i = 0; i < dotNum; i++) {
            dots.children[i].classList.remove('current')
        }
        dots.children[index % dotNum].classList.add('current')
        animateSlow(imgs, -index * w)
    })

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

    // 不能事件委托到ul身上 因为容易误触,ul没有index属性返回null,图片滑动回第一张
    // dots.addEventListener('mouseover', function (e) {
    //     for (var i = 0; i < len - 1; i++) {
    //         dots.children[i].classList.remove('current')
    //     }
    //     console.log(e.target);
    //     e.target.classList.add('current')
    //     let index = e.target.getAttribute('data-index')
    //     console.log(index);
    //     animateSlow(imgs, -index * w)
    // })
})

案例:带有动画的返回顶部	window.scroll(x,y)

function animateSlow(obj, target, callback) { //目标对象 目标位置
    clearInterval(obj.timer)
    obj.timer = setInterval(function () {
        var step = (target - window.pageYOffset) / 10;
        if (window.pageYOffset == target) {
            clearInterval(obj.timer)
            callback && callback();
        } else {
        if (Math.abs(step) <= 1) {
        	window.scroll(0, target)
        } else {
       		window.scroll(0, window.pageYOffset + step)}}}, 20)
}
animateSlow(window, 0)

2. 移动端特效

移动端浏览器兼容性较好,不需要考虑以前JS的兼容性问题,可以放心使用原生JS书写效果,但移动端也有 自己独特的地方。比如触屏事件touch,Android和IOS都有。

1. 触屏事件

  1. 触屏事件

    touch对象代表一个触摸点,触摸点可能是一根手指或触摸笔。触屏事件可响应其对屏幕或触控板操作。常见触屏事件如下:

    touch触摸事件说明(都有自己各自的事件对象)
    touchstart手指触摸到一个DOM元素时触发
    touchmove手指在一个DOM元素上滑动时触发,默认移动屏幕操作,e.preventDefault()阻止
    touchend手指从一个DOM元素上移开时触发
  2. 触摸事件对象(TouchEvent)

    touchEvent是一类描述手指在触摸平面的状态变化事件,这类事件用于描述一个或多个触点,使开发者可以检测触点的移动、增加和减少等,可以得到触点的坐标

    触摸列表说明
    touches正在触摸屏幕的所有手指的一个列表
    targetTouches正在触摸当前DOM元素上的所有手指的列表
    changedTouches手指状态发生了改变的列表,从无到有,从有到无的变化
  3. 案例:移动端拖动元素

    • 方案1:DOM元素相对于触点坐标不变
    • 方案2:DOM元素初始位置 + 触点的移动距离

2. 移动端常见特效

移动端轮播图——独特之处:


1. 无缝滚动 需要将第一张添加到最后一张后,需要将最后一张添加到第一张前,因为pc端为鼠标点击,可以实现快速跳转,但是移动端为触摸点拖动,来不及快速跳转

图片编号: 3 1 2 3 1
索引编号: -1 0 1 2 3    

2. .focus ul {width: 500%; }  //需要装多少张图片,就将宽度设置为x倍
移动端有个很大的问题,宽度是根据父元素确定的,当上面ul的宽度为 500% 时,
ul li img 继承的宽度也是 500% ,不是我们想要的效果
所以需要给 li 限制宽度,li继承ul, 所以li 的 width 为 1/5* 100%
    
3. 因为移动端没有兼容的问题,可以放心使用css3,所以不需要麻烦js动画函数
可以直接用过渡效果  transition: all .3s 
但播放到最后一张要实现快速跳转 需要监听过渡完成事件 transitionend

4. 当前小圆点有单独的样式属性 定义在current类,可以通过切换类实现点击小圆点current
element.classList.toggle('className');
//原始写法
for (var i = 0; i < dots.length; i++) {
	dots[i].classList.remove('current')}  
//最新写法
ol.querySelector('.current').classList.remove('current')
ol[index].classList.add('current')

5. 手指滑动轮播图:本质就是ul跟随手指移动,简单来说就是移动端拖动元素
设置一个 标准 滑动距离超过则上/下一张, 不超过则恢复
由于小圆点对应高亮显示代码由transitionend事件触发
index只能取 0,1,2,而实际上index可以取 -1,0,1,2,3
所以在触点离开事件里,还需要当 index=30  index=-1 则取 2

瀑布流 实现原理
多行等宽元素排列,后面的元素依次添加到其后。
即:等宽不等高,图片按比例缩放至设定宽度,依次往后追加
注意:
1. 第二行 并不是按照左对齐一次排放的,而是会插入第一行所有列高度最小的元素下方
2. 父元素清除浮动,高度取列表数组的最大值

3. 移动端常用开发插件

移动端要求是快速开发,所以经常需要借助一些插件。

js插件就是js文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用,如轮播图和瀑布流插件

特点:一般是为了解决某个问题存在的,功能单一,文件小

click 延时解决方案

移动端click事件会有 300ms 的延时,原因是移动端双击会缩放(double tap to zoom)页面

解决方案:

1. 禁用缩放:<meta name="viewport" content="user-scable=no">
2. 利用touch事件自己封装这个事件解决300ms延时
    1. 记录首次触摸屏幕时间
    2. 记录离开屏幕时间  减去 获得 2次触摸间隔
    3. 间隔时间小于150ms,并且没有滑动屏幕,则定义为点击
3. fastclick插件:网址:https://github.com/ftlabs/fastclick
2. 利用touch事件自己封装这个事件解决300ms延时 1. 记录首次触摸屏幕时间 2. 记录离开屏幕时间 减去 获得 2次触摸间隔 3. 间隔时间小于150ms,并且没有滑动屏幕,则定义为点击 3. 移动端要求是快速开发,所以经常需要借助一些插件 js插件就是js文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用,如轮播图和瀑布流插件 特点:一般是为了解决某个问题存在的,功能单一,文件小 网址:https://github.com/ftlabs/fastclick

1. Swiper插件的使用

    1. 引入插入相关文件
    2. 按照规定的语法使用
    3. 使用方法:https://www.swiper.com.cn/usage/index.html
    4. 注意不要更改里面的结构和类名,不然css和js都要对应更改,较为麻烦 

2. TouchSlide/superslide插件
    TouchSlide 是纯javascript打造的触屏滑动特效插件,面向手机、平板电脑等移动终端,
    能实现触屏焦点图、触屏Tab切换、触屏多图切换等常用效果。
    插件开源、体积小、简单实用、功能强大,是你架构移动终端网站的重要选择!
    
3. zy.media.js
	H5 提供 video 标签,但浏览器的支持情况不同
    不同视频格式文件,可以通过source解决
    但是外观样式、还有 暂停、播放、全屏等功能只能自己写代码解决
    可以通过插件方式制作

插件使用总结

  1. 确认插件实现的功能
  2. 去官网查看使用说明
  3. 下载插件
  4. 打开demo实例文件,查看需要引入的相关文件,并引入
  5. 分别复制demo实例文件中的html、css和js代码

4. 移动端常用开发框架

什么是框架:顾名思义就是一套架构,基于自身的特点向用户提供一套完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。

前端常用框架:bootstrapVueAngularReact 等,既能开发PC端,也能开发移动端
前端常用移动端插件:swipersuperslideiscroll

总结:框架大而全,一整套解决方案;插件小而专一,某个功能的解决方案

jQuery

jQuery是JavaScript库,是封装好的特定的函数或方法的集合,比如获取元素、animate、hide、show等

作用:优化DOM操作,事件处理,动画设计和Ajax交互

原生JavaScript(楼梯)—— Jquery(电梯)

特点:轻量级、跨浏览器兼容、支持插件扩展,免费开源,链式编程、隐式迭代

使用css选择器选取元素,作为为客户端脚本库,可以和Ajax一起使用。简写为$符号

注意:Jquery对象只能使用Jquery方法,DOM对象只能使用JS原生方法,不能混用,因为互不认识,jQuery用$() 将DOM对象以伪数组的形式封装为jQuery对象。但二者之间需要转换,因为jQuery毕竟只封装了常用的、使用频率高的DOM方法,所以还有用原生DOM API的需求。

基础语法:$(selector).action() //$其实就是jQuery的别称,同时也是jQuery的顶级对象,相当于原生JS中的window。

入口函数
1. $(function(){   //相当于window.addEventListener('load', function())
	--- jQuery functions go here ----
})
2. $(document).ready(function(){   //相当于window.addEventListener('DOMContentLoaded', function())
	--- jQuery functions go here ----
	});

DOM对象转换为jQuery对象:$(DOM对象)
jQuery对象转换为DOM对象:$('jQuery对象')[index]    $('jQuery对象').get(index)

JQuery常用API
1. 选取元素:$("css选择器")

2.样式操作  $("css选择器").css("属性", "属性值")  $("div").css("color", "pink") //所有div都会变色(隐式迭代)
	隐式迭代:Jquery对象以伪数组的形式存储DOM元素,其遍历内部DOM的过程叫做隐式迭代
     简单理解:jQuery会给匹配到的所有元素进行遍历循环,执行对应的方法,不用我们手动循环伪数组
     
3. 筛选选择器:类似于css的 结构为类选择器 E:nth-child(n)

4. 筛选方法:parent(亲爸爸) children(亲儿子)  parents(列祖列宗) find(后代) siblings(兄弟们) eq(第几个)

5. 排他思想
	先设置自己的样式A,再设置其它兄弟的样式B
     $('button').mouseover(function () {   
         $(this).css('backgroundColor', '#f5f5f5');
         $(this).siblings().css('backgroundColor', '#fff')
     });
6. 链式编程(yyds)
	$('button').mouseover(function () {   
         $(this).css('color', '#f5f5f5').siblings().css('color', '#fff')
     });
6. 得到当前元素的索引号 $(this).index()  这个太棒了!!!可以做选项卡tab栏标签和内容对应切换案例

7. JQuery效果:
	显示/隐藏/切换 show([speed],[callback])  hide()  toggle()
	淡入/淡出 fadein([speed],[callback]) fadeout()  fadeToggle()
	上拉/下拉 slideUp([speed],[callback]) slideDwon()  slideToggle()
	动画 animate({params},speed,callback)
	动画和效果的区别,动画的父亲要加定位,因为有位置的偏移,效果只是一种transition过渡罢了
	stop() 方法用于停止动画或效果事件的排队,清空队列,防止短时间多次触发导致效果反复执行情况产生
 
8. 属性操作
	1. prop设置/获取属性
	$('input').prop('checked', 'true') //设置自带属性
	$('input').prop('checked')   //获取自带属性
	2. attr设置/获取属性
	$('input').attr('data-index', '1')  //设置自定义属性,也可以设置自带属性
	$('input').attr('data-index') //获取自定义属性。其实也可以获取自带属性  全能王
	2. data数据缓存 方法里的数据是放在元素的内存里面的,也可以获取自定义属性
	$('span').data("uname", "andy") 

9. 内容文本值
	html() 获取元素内容  相当于 innerHTML
    html('内容')  设置内容   
    text()   相当于innerText  只想得到文本
	text('内容')
	$('input').val() 获取表单元素的值
    
10. 元素操作
	主要是遍历、创建、添加、删除元素操作(增删查改)
    1. 遍历
    $(selector).each(function(index, domEle){}) 具体理解看我另一篇文章
    $.each(arr, function(index, value){})    主要用于遍历数据、处理数据、对象,全能王
    2. 添加元素
    append() prepend() - 子元素添加      before()   after() - 兄弟元素添加
  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值