jQuery基础

JQuery学习

承接之前WebAPI补充

// 增加一个类名
// 给每个元素都增加了一个属性 classList
// classList还有4个方法
// classList.add() 只负责添加类名,不用担心原来的类名会被覆盖
// classList.remove() 只负责移除一个类名
// classList.contains() 判断是否包含了某个类名
// classList.toggle()  切换类名 如果有这个类名,就删除这个类名, 如果没有这个类,增加这个类名
// 过渡结束事件
// 当某个元素有过渡,过渡结束时,就会触发transitionend事件
// 对于C3提供的一些新事件,需要使用addEventListener

// 表单文本框事件
// onchange : 当文本框的value值发生改变的// 判断内容改变的时候触发,,,,// 等待你的输入完成
// oninput :  给文本框输入内容的时候    // 在输入的时候实时的触发这个事件

// 音视频
// timeupdate : 视频播放中,事件发生改变就会触发

// 获取鼠标滚轮事件
// mousewheel :鼠标上的滚轮滚动的时候触发该事件 
// 针对这些新的事件最好使用addEventListener注册事件
// 通过事件对象e.wheelDelta 判断是往上滚还是往下滚
// 向上 120  向下 -120 (不同的浏览器里可能不同,在Chrome中是这样的)

 // js 获得盒子距离窗口的距离的集合的函数
// var rolePos = box.getBoundingClientRect();
// var roleX = rolePos.left;

// 在jQuery中属性offset.left 获取的和这个是一样的

jQuery初识

jquery版本问题
1.x : 兼容ie678 1.12.4 (我们主要是使用这个)
2.x : 不兼容ie678

// jQuery入口函数 --->入口函数: 等待页面的加载完成,才会执行代码
// 方法一
$(document).ready(function(){

});
// 方法二(常用这个,比较简单)
$(function(){

});
// 入口函数的好处
// 1. 保证元素正确加载
// 2. 形成一个沙箱

// jquery入口函数和window.onload的对比
// 1. jquery的入口函数可以写多个,不会覆盖。
// 2. jquery的入口函数执行要比window.onload早。jquery的入口函数只会等页面加载,不会等待图片的加载。

DOM对象与JQuery对象

通过js的方式获取到的页面中的元素其实都是DOM对象,DOM对象有自己的属性和方法

// 使用JavaScript中的方法获取页面中的元素返回的对象就是dom对象
var box = document.querySelector("#box");

通过jquery的方式获取到的页面中元素就是jquery对象,jQuery对象也有自己的属性和方法

$("#box")  // 通过 $ 获取的对象属于jQuery对象
// 区别
//  DOM对象不能调用jquery对象的方法
//  jquery对象也不能调用DOM对象的方法
// 关联:  jquery是对DOM的封装  jquery对象是DOM对象的一个集合,内部放的DOM对象

DOM对象和jQuery对象之间的转换

/* 
    DOM对象:通过webapi中的方法获取到的对象是DOM对象, 只能调用DOM自己的方法

    jquery对象: 通过jquery的方法获取到的对象,,,,jquery对象内部封装了很多的DOM对象,jquery对象自己提供了很多的方法,这些方法都是用了内部的DOM对象。

    DOM对象不能直接调用jquery的方法,想调用,需要把DOM对象变成jquery对象  $(dom)
    jquery对象也不能直接调用DOM的方法,把jquery内部的DOM对象取出来。 jQuery对象其实就是DOM对象的包装集(包装了DOM对象的集合(伪数组)),因此只要挨个取出来就可以直接使用DOM的属性和方法
*/
var lis = $("li");
//第一种方法(推荐使用)
lis[0]
//第二种方法
lis.get(0)

jQuery选择器

jQuery选择器是jQuery为我们提供的一组方法,让我们更加方便的获取到页面中的元素。注意:jQuery选择器返回的是jQuery对象。

css选择器

跟css选择器一样

名称用法描述
ID选择器$(“#id”);获取指定ID的元素
类选择器$(“.class”);获取同一类class的元素
标签选择器$(“div”);获取同一类标签的所有元素
并集选择器$(“div,p,li”);使用逗号分隔,只要符合条件之一就可。
交集选择器$(“div.redClass”);获取class为redClass的div元素
子代选择器$(“ul>li”);使用>号,获取儿子层级的元素,注意,并不会获取孙子层级的元素
后代选择器$(“ul li”);使用空格,代表后代选择器,获取ul下的所有li元素,包括孙子等

过滤选择器

这类选择器都带冒号 :

名称用法描述
:eq(index)$(“li:eq(2)”).css(“color”, ”red”);获取到的li元素中,选择索引号为2的元素,索引号index从0开始。
:odd$(“li:odd”).css(“color”, ”red”);获取到的li元素中,选择索引号为奇数的元素
:even$(“li:even”).css(“color”, ”red”);获取到的li元素中,选择索引号为偶数的元素
:first$(“li:first”).css(“color”, ”red”);获取到的li元素中的第一个
:last$(“li:last”).css(“color”, ”red”);获取到的li元素中的最后一个
:checked$(“input:checked”)匹配所有选中的被选中元素

筛选选择器(方法)

筛选选择器的功能与过滤选择器有点类似,但是用法不一样,筛选选择器主要是方法。

名称用法描述
children(selector)$(“ul”).children(“li”)获取当前元素的所有元素中的li元素,selector不写表示获取所有子元素
find(selector)$(“ul”).find(“li”);获取当前元素中的后代元素中的li元素
siblings(selector)$(“#first”).siblings(“li”);查找兄弟节点,不包括自己本身。
parent()$(“#first”).parent();查找父亲
eq(index)$(“li”).eq(2);相当于$(“li:eq(2)”),index从0开始
next()/nextAll ( “ l i ” ) . n e x t ( ) / (“li”).next()/ (li).next()/(“li”).nextAll()找下一个兄弟/查找后面所有兄弟
prev()/prevAll() ( “ l i ” ) . p r e v ( ) / (“li”).prev()/ (li).prev()/(“li”).prevAll()找上一次兄弟/查找前面所有兄弟

mouseenter和mouseleave

  1. mouseover与mouseout是一对事件,当鼠标经过当前元素或者当前元素的子元素的时候,mouseover事件都会触发【事件冒泡】。
  2. mouseenter与mouseleave是一对事件,只有当鼠标经过当前元素时,事件会触发,鼠标经过子元素,mousenter事件是不会触发的
// mouseenter和mouseleave事件只有在进入或者离开父元素时才会触发, 在子元素上不会触发
// mouseover和mouseout进入或者离开父元素会触发,进入或者离开子元素也会触发

index()方法

// index() 方法:
// 获取的是当前元素在它所有兄弟元素中的索引 

注意坑

<body>
  <ul>
    <li><a href="#">我是一个连接</a></li>
    <li><a href="#">我是一个连接</a></li>
    <li><a href="#">我是一个连接</a></li>
    <li><a href="#">我是一个连接</a></li>
  </ul>
  <script src="jquery-1.12.4.js"></script>
  <script>
    $(function(){
      $("a").click(function() {
        console.log($(this).index());  // 输出的都是 0 ,因为a标签没有兄弟元素
        console.log($(this).parent().index());   // 输出的下标是正确的
      })
    });
  </script>
</body>

JQuery操作样式

// 隐式迭代:
// 设置操作的时候,如果是多个元素,那么给所有的元素设置相同的值
// 获取操作的时候,如果是多个元素,那么只会返回第一个元素的值。

修改行内样式 CSS()方法

// 设置单个样式  css(name, value)
// 参数: name: 样式名  value: 样式值
$('li').css('backgroundColor', 'pink');
$('li').css('fontSize', 50);
$('li').css('color', 'red');
// 可以设置多个样式,传一个对象进去
// css(obj)   css({})
$('li').css({
  backgroundColor: 'pink',
  fontSize: 50,
  color: 'red'
});
// 获取样式 css()
// css(name)  需要获取的样式的名字
// 注意:获取样式操作只会返回第一个元素对应的样式值。
console.log($('li').css('fontSize'));

修改类名 Class方法

// addClass(name): 添加类名
// removeClass(name): 移除类名
// toggleClass(name): 切换类名,有就删除类名,没有就添加类名
// hasClass(name): 是否有某个类名

$('li').addClass('base dd ee');
$('li').addClass('red');
$('li').removeClass('bb');
$('li').toggleClass('cc');
$('li').toggleClass('cc');
console.log( $('li').hasClass('red')  );

jQuery操作属性

attr

// jquery中操作属性: attr 用法和css的用法是一样
// attr操作标签的属性的   css用来操作样式的
// attr(name, value)
// 作用:设置单个属性 
// name:属性名  value:属性值
$('img').attr('title', '呜呜');
$('img').attr('alt', '无法显示');

// attr(obj)
// 设置多个属性
$('img').attr({
  src: '01.jpg',
  title: '呜呜'
});

// 获取属性的值
// attr(name)
console.log( $('img').attr('title') );
console.log( $('img').attr('alt') );

// removeAttr() : 删除一个属性
$('img').removeAttr('title');

prop

布尔属性的处理

// 使用attr修改元素的属性
// 自从1.6版本开始,布尔类型的属性checked disabled selected不再使用attr操作,使用prop来操作。  prop方法和attr方法的用法一模一样。
$('button:first').click(function() {
  $('input').prop('checked', true);
  console.log($('input').prop('checked'));
});

$('button:last').click(function() {
  $('input').prop('checked', false);
  console.log($('input').prop('checked'));
});

动画

三组基本动画

1、显示隐藏

show()、hide()、toggle() 如果不写时间,没有过渡效果

// 作用: 让一个元素显示
// 修改了元素的width 和 height 和opacity 进行动画
// 参数1:
//    1. 如果没有参数,没有动画效果
//    2. 参数可以指定为一个时间, 毫秒值, 动画的时间
//    3. 参数还可以是固定的字符串, fast:快=200ms normal:正常=400ms slow:慢=600ms
// 参数2:
//    回调函数, 表示当动画执行完成后,这个函数 就会调用
// $('div').show();
$('div').show(1000, function() {
  console.log('动画执行完成了');
});
$('button').eq(1).click(function() {
    $('div').hide(1000);
});
$('button').eq(2).click(function() {
  // 如果是显示状态,就会隐藏, 如果是隐藏装填,就会显示
  $('div').toggle(1000);
})

2、淡入淡出

fadeIn()、fadeOut()、fadeToggle() 不写参数默认时间是normal

$('button').eq(0).click(function() {
  // fade系列:用来让一个元素淡入和淡出的效果
  // 作用:淡入  慢慢的显示出来  修改是透明度
  // 参数1: 如果没有,默认是normal
  // $('div').fadeIn(1000);
  $('div').fadeIn(1000, function() {
    console.log('动画结束了');
  })
});

3、滑入滑出

slideDown()、slideUp()、slideToggle() 不写参数默认时间是normal

// 作用:滑入  慢慢的向下滑出,类似于卷帘门  修改是height
$('button').eq(0).click(function() {
  // $('div').slideDown();
  $('div').slideDown(1000);
});

$('button').eq(1).click(function() {
  $('div').slideUp();
});
//  转场动画
$('button').eq(2).click(function() {
  $('div').slideToggle();
});

4、自定义动画

animate()

/* 
  功能: 给元素执行自定义动画
  参数1: 必填
    指定需要执行动画的样式, 是一个对象
  参数2   指定动画的时间 默认是normal
  参数3   指定动画效果   默认:swing(秋千,摇摆) 先慢后快再慢  linear
  参数4: 函数, 动画结束后就会执行
*/
$('div').eq(0).animate({left: 1000}, 5000);
$('div').eq(1).animate({left: 1000}, 5000, 'linear', function() {
  console.log('动画执行结束了');
});

定义一系列的动画

// 回调地狱
// 方法一
$('div').animate({left: 400}, function() {
  $('div').animate({width: 300}, function() {
    $('div').animate({height: 300}, function(){
      $('div').animate({borderRadius: 150})
    })
  })
});
// 方法二(推荐使用)
$('div').animate({left: 400})
        .animate({width: 300})
        .animate({height: 300})
        .animate({borderRadius: 150})

5、动画队列和停止动画

jquery为了保证动画不丢失, 把所有要执行的动画都保存到一个动画队列中,动画一个一个执行。
stop()一般写在animate()的前面,意思是:结束之前的动画,开始接下来的动画
如果把stop()写在animate()的后面,这样这个动画才执行了1帧就被暂停了

 $(function(){
  $('button').eq(0).click(function() {
    $('div').stop(true).slideDown(2000);
  })

  $('button').eq(1).click(function() {
    // 停止当前这个执行的这个动画
    // 参数1: 是否清除动画队列 clearQueue false
    // 参数2: 是否跳转到当前动画最终效果 false  true
    $('div').stop(false, false);
  })
});

节点操作

创建节点

//$(htmlStr)
//htmlStr:html格式的字符串
$('<span>这是一个span元素</span>');
$("<span></span>").text("这是一个span元素");

// 总结 $() 用法
$(function(){})     // 入口函数
$('button')         // 选择器
$(document)         // 把DOM对象转成jquery对象
$('<button>按钮</button>')  // 创建节点

添加节点


/*  内部插入  */
// parent.append(child)  把child追加到parent的子元素最后面
// append() 给元素追加一个子元素
$('div').append( $('p') );
$('div').append( $('<p>这是新建的p标签</p>') );

// prepend: 给元素的子元素最前面添加一个元素  
$('div').prepend( $('p') );    //  把child追加到parent的子元素最前面

// child.appendTo(parent)  作用相当于   parent.append(child) 把child追加到parent的子元素最后面
$('div').append( $('p') );
$('p').appendTo($('div'));

// child.prependTo(parent) 相当于  parent.prepend(child)
$('p').prependTo( $('div') );
$('div').prepend( $('p') );

/* 外部插入 */
// before:    node.before(node1)
// after:     node.after(node1)
// 把p添加到div的前面,作为兄弟元素
$('div').before( $('p') );
// 把p添加到div的后面,作为兄弟元素
$('div').after( $('p') );

// insertBefore :把所有匹配的元素插入到另一个、指定的元素元素集合的前面。
$("p").insertBefore("#foo");  // 把所有的p插入到#foo的前面 
// insertAfter :把所有匹配的元素插入到另一个、指定的元素元素集合的后面
$("p").insertAfter("#foo");  // 把所有的p插入到#foo的后面

// 可以允许是一个选择器,不一定是jQuery对象
// append(selector)
$('p').appendTo('div');  // 把p插入到div标签中

清空节点、移除节点和克隆节点

empty:清空指定节点的所有子元素,自身保留(清理门户)
remove:相比于empty,自身也删除(连自己都不放过)

$("div").empty();//清空div里面的所有内容(推荐使用,会清除子元素上绑定的内容)
$("div").remove(); // 自身调用就是删除自身

clone() 参数:true/false

$(selector).clone();    // 等价于 clone(false) 参数默认是false  深克隆,克隆标签和内容,但是不会克隆事件
$(selector).clone(true); // 深克隆 ,克隆标签和内容,并且会克隆事件

特殊属性

val()

val方法用于设置和获取表单元素的值,例如input、textarea的值

  • 没有参数,就表示获取value值
  • 参数,就表示设置value值
//设置值
$("#name").val(“张三”);
//获取值
$("#name").val();

text()和html()

// text方法相当于 innerText属性
// html方法相当于 innerHTML属性
// 有参数是设置,无参数是获取
$('li').text('222');
$('li').html('<h3>哈哈</h3>');

width()与height()

// 宽度和高度一样
 // width() : 获取盒子的宽度
// 用法 $box.width()
// 设置宽度
// $('div').width(200);
// width() 用来获取盒子的width宽度
console.log( $('div').width() );
// innerWidth();  用来获取盒子 的padding + width
console.log( $('div').innerWidth() );
// outerWidth(false); 用来获取盒子的 padding + border + width
console.log( $('div').outerWidth() );
// outerWidth(true)  padding + border + width + margin
console.log( $('div').outerWidth(true) );
// height()  innerHeight() outerHeight(false)  outerHeight(true)

// width() 和 height() 可以用于获取屏幕的宽度和高度
$(window).resize(function() {
// console.log(window.innerWidth);
  console.log($(window).width());
  console.log($(window).height());
});

scrollTop()和scrollLeft()

// 无参数是获取,有参数是设置
$(window).scroll(function() {
  console.log($(this).scrollTop());  
});
$('button').click(function() {
  $(window).scrollTop(0);
});
/* 
获取页面的scrollTop
  jq中:  $(window).scrollTop()
  js中:  window.pageYOffset 或者  document.documentElement.scrollTop

设置scrollTop
  jq:    $(window).scrollTop(0)
  js:    document.documentElement.scrollTop = 0
*/
// 点击按钮让页面回到顶部
$btn.click(function() {
  // 因为这里用了动画,所以我们不能直接使用window.scrollTop(0),这样是直接蹦会顶部没有过度效果
  // 所以这里我们需要给html设置scrollTop属性
  // document.documentElement.scrollTop=0;
  $('html').animate({
    scrollTop: 0
  }, 2000);
});

offset()和position()

offset方法获取的是盒子在整个body中的位置
position方法获取的是盒子距离有定位的最近的父元素的位置 offsetLeft offsetTop

//获取元素距离document的位置,返回值为对象:{left:100, top:100}
$(selector).offset();
//获取相对于其最近的有定位的父元素的位置。
$(selector).position();

JQuery事件机制

简单事件注册

//  优点: 相比js来说,注册的事件不会覆盖
//  缺点: 没法取消,并且不能给动态创建的标签注册事件
click(function(){})            //单击事件
mouseenter(function(){})       // 鼠标进入事件
mouseleave(function(){})       // 鼠标离开事件

bind()和unbind()

// 优点: 可以移除事件
// 缺点: 无法给动态创建的元素注册事件
// 参数1: 事件名
// 参数2: 函数,事件处理程序
$('button').bind('click', function() {
  console.log('哈哈');
});
// 解绑事件,用unbind也可以解绑简单事件注册的
$('button').unbind('click');

delegate()和undelegate()

换成白话说: 我把某个事件委托给了ta的一个父元素,当这个父元素中的某个子元素满足条件时就自动获得这个事件

// 给需要注册的子元素的公共的父元素去注册这个委托事件
// 参数1: 选择器, 指定谁来触发这个事件
// 优点:可以给动态创建的元素添加事件
// 缺点:只能实现委托事件
// 1. 给父元素注册
// 2。一定要指定触发的元素,  最终事件还是交给了子元素
// 给div注册了委托事件,当这个div里的p点击的时候,就触发事件
$('div').delegate('p', 'click', function() {
  console.log('哈哈');
  console.log(this);   // 这个this指向的是 这个 p标签
});

on()和off() (重点)

on是之前三种的一个整合,用一个on可以实现前面的三种

 // 注册自己的事件 等价于  事件名注册和bind()注册
// 参数1:注册的事件名
// 参数2: 函数
$('button').on('click', function() {
  $('<p>这是一个新p</p>').appendTo('div');
});

// 如果要注册委托事件  等价于delegate注册事件
// 但是on参数的顺序和delegate参数顺序不一样
// 参数1; 事件名
// 参数2: 必须指定触发的元素
// 参数3: 函数
$('div').on('click', 'p', function() {
  console.log('哈哈');
  console.log(this);   // 同样指向的是p
})

解绑事件off()

// 移除事件
// off() 会把div身上所有的事件全移除
$('div').off();

// off('click') 移除click事件
// 参数1: 事件的类型
$('div').off('click');

// off也可以移除委托事件
// 移除div的委托事件, 给p的事件移除,一般可以用 ** 表示移除委托事件
$('div').off('click', '**');

触发事件trigger()

$(function(){
  $('button').on('click', function() {
    console.log('这是给button注册的事件');
  });

  $('input').on('click', function() {
    // 触发button的点击事件
    // 触发的方式1: 直接调用事件名
    // $('button').click();
    // 触发事件方式2  trigger():触发   toggle():切换
    $('button').trigger('click');
  });
});

补充知识

事件对象

  • e.stopPropagation() 阻止事件冒泡
  • e.preventDefault(); // : 阻止浏览器默认行为
  • return false; 即可阻止事件冒泡, 也可以阻止浏览器的默认行为
$("div").on('mousedown', function (e) {
  var x = e.offsetX;
  var y = e.offsetY;
  console.log(e.offsetX, e.offsetY);
});
// e.offsetX 是鼠标点击位置距离盒子自身左边的距离
// e.offsetY 是鼠标点击位置距离盒子自身上边的距离

链式编程

链式编程: jquery中允许我们一直调用jquery的方法,可以一直链式下去。

// 要求: 只有设置性的操作才可以链式编程, 因为设置性操作不会修改jquery对象,返回当前这个jquery对象
// 如果是jquery的获取操作 width()val()text() css('backgroundColor')不能继续链式编程了,因为返回的是某个值不是jQuery对象

end()方法

/* 
  在链式编程中,当我们查找当前元素的兄弟元素时会导致改变jQuery对象,
  这时我们可以通过end()使得我们指向的jQuery对象回到上一个
*/
$(this).text('★').prevAll().text('★').nextAll().text('☆');  // error
/* 
  分析:
    1、$(this).text('★')  ---> 当前的li,返回的结果也是指向当前的li
    2、$(this).text('★').prevAll() ----> 指向的当前li之前的兄弟节点   ---> 此时已经不再是指向我选择的那个li了
    3、$(this).text('★').prevAll().text('★').nextAll() ---> 这里的nextAll()就不再是当前li后面的兄弟了
*/
// 方法一
$(this).text('★');
$(this).prevAll().text('★');
$(this).nextAll().text('☆');
// 方法二
$(this).text('★').prevAll().text('★').end().nextAll().text('☆').end();
/* 
  分析:
    1、$(this).text('★').prevAll().text('★').end() ----> 使用了end()方法后,使得返回的对象又是我选择的那个li
    $(this).text('★').prevAll().text('★').end().nextAll().text('☆') ---> 所以可以直接修改当前li后面的兄弟
*/

// end()原理
// 在jQuery对象中有一个属性prevObject ,这个属性指向的就是我上一次的jQuery对象,使用end()后就会重新让返回的jQuery对象变为我之前的

隐式迭代和显示迭代

隐式迭代: 偷偷的 遍历: jquery对象不需要自己写for循环,因为在jquery方法内部会自动遍历。
如果是jquery的设置操作, jquery的方法都会自动写for循环,给所有的元素都设置一样的值。
如果是jquery的获取操作, jquery方法直接返回第一个元素的样式

// 显示迭代
// jquery对象可以遍历
// jquery会让每个元素都执行一次这个函数
// i: 每个元素的下标
// e: 每个元素 (一般都不用,因为直接可以用this)
// this: 每个元素
$('li').each(function(i,e){
  $(this).css('opacity', (i + 1) / 10)
});

多库共存

jQuery使用 作 为 标 示 符 , 但 是 如 果 与 其 他 框 架 中 的 作为标示符,但是如果与其他框架中的 冲突时,jQuery可以释放$符的控制权.

 var c = $.noConflict();  // 这样就把$ 的权限释放给了c,之后我就可以用c来代替之前的$了

//  比如,入口函数
c(function() {
  console.log(c);
  console.log($);
})
/* 
  原理解释:
  jQuery.noConflict = function( deep ) {
    if ( window.$ === jQuery ) {
      window.$ = _$;
    }

    if ( deep && window.jQuery === jQuery ) {
      window.jQuery = _jQuery;
    }

    return jQuery;
  };

  if ( !noGlobal ) {
    window.jQuery = window.$ = jQuery;
  }
  这是jQuery文件里的源码(最后面)
  我们通过上面的可以知道,jQuery文件给我们暴露的就两个变量 $ 和jQuery,在noConflict中把之前保存的值放在了_$ 中,当我们调用这个方法的时候,重新返回出来,保存到我们变量中去,之后就可以直接用了
*/

jQuery插件

// http://www.jq22.com/ 是一个jQuery的插件常用的网站
// jquery插件的使用步骤
// 1. 引入jquery
// 2. 引入jquery插件
// 3. 使用jquery插件

jquery.color.js // 可以让颜色也有动画的效果  https://github.com/jquery/jquery-color
jquery.lazyload.js  // 懒加载,如果一个网页过长,可以让下面的图片不一开始就加载,只有滚到那个位置的时候在加载  https://github.com/tuupola/jquery_lazyload

封装一个插件

// 这个其实就是给原型对象增加一个共享的方法
$.fn.xxx = function(){

};

// 例子 -- 封装拖拽盒子的功能
$.fn.drag = function() {
  // 使用变量把this给存起来
  var that = this;
  that.on('mousedown', function(e) {
    e.preventDefault();
    var x = e.offsetX;
    var y = e.offsetY;
    $(document).on('mousemove', function(e) {
      that.css({
        position: 'absolute',
        left: e.pageX - x,
        top: e.pageY - y
      });
    });
  });
  that.on('mouseup', function() {
    $(document).off('mousemove');
  });
  return that;
};
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值