前端入门(一)JavaScript语法、数据类型、运算、函数、类、DOM

概念

  • JavaScript是用于浏览器交互操作的脚本语言。
  • 为了确保不同的浏览器上运行的JavaScript标准一致,所以几个公司共同制定了JS的标准命名为ECMAScript

JavaScript编写的位置

  • 写在HTML中的script标签中
  • 写在.js文件中,然后在script标签中使用src引入
  • 写在按钮标签的"onclick"属性中
  • 写在超链接标签"href"属性中

JS既有专门的.js文件,在html文件中使用script标签,添加src属性引入js文件,也可在html文件中直接使用,用script标签,script标签必须成对出现
在这里插入图片描述
三个简单的JavaScript语句:

  • alert(“弹窗信息”):控制浏览器弹出一个警告框
  • document.write():让计算机在页面中输出一个内容,即向body输出一个内容
  • console.log(“控制台输出内容”): 向控制台输出一个内容

js代码也可以写在标签的属性中,但是他们属于结构与行为耦合,不方便维护。

在这里插入图片描述

基本语法

  • JS中严格区分大小写
  • JS中每一条语句都以分号(;)结尾,如果不写分号,浏览器会自动添加,但是会消耗一定的系统资源
  • JS中忽略多个空格和换行

JS中只有var类型变量,语句类似于Java。
在浏览器中调试JS需要注意:

在这里插入图片描述Element:元素(html框架)
Console:命令控制台,如console.log(“”/var),控制台输出,相当于print
Sources:源码
Network:抓包
Application:应用,查看缓存等

数据类型

JS中共有6大数据类型:

  • number: 数字类型,JS中不分小数和整数
  • string:字符串类型
  • boolean:布尔值类型
  • object:对象类型
  • function:函数类型
  • undefined:未定义类型

使用 JavaScript 的 typeof 来确定 JavaScript 变量的类型:
使用instanceof()返回对应类型对象的实例。

变量声明var、let、const

letconst是ES6新增的关键字
var、let、const的区别在于:

  • let和var用来声明变量,而const用来声明常量,但是const声明的引用类型是可以改变的
  • var是函数作用域,let是块作用域
    • var是函数作用域,在整个函数内都是有效的,在for循环内定义一个var变量,实际上在for循环外,函数内,都是可以访问的
    • let和const是块级作用域,只在代码块内有效,例如for循环内定义的,for循环外不可访问。 所谓块级作用域,就是用{}包含的区域,我们常用的有for,while,if等。但是在块级作用域中用let声明变量,那么此变量就有了块级作用域,就必须只有在此块级作用域才能访问此变量。
    • const实际保证的并不是变量的值不可变,而是变量指向的内存地址不可变,有点类似Java中的final,因此,对象不可变,对象的属性是可变的。
    • 如果在全局作用域使用var声明变量,此变量会默认成为window的一个属性
    • var声明的变量有变量提升特性,let声明则没有这个特性,所谓变量提升,就是js引擎把变量的声明部分和函数的声明部分提升到代码开头的行为;变量提升后,会给变量默认赋值为undefined

例如下边代码:

console.log(a)
var a = 1

这里会打印undefined,这是因为变量提升后,实际代码是下边这个样子:

var a
console.log(a)
a = 1

undefined与null的区别

  • undefined表示只定义了变量,并没有给变量赋值
  • null表示数值为空值,给变量赋了null

undefined 与 null 值相等,但类型不相等

注意:

  • == 表示值相等,使用===表示值和类型都相等
  • != 表示值不相等,使用!==表示值或者类型不相等
typeof undefined              // undefined
typeof null                   // object
null === undefined            // false
null == undefined             // true

数值类型number

Js中只有一种数值类型
写数值时,不用小数点即可,超大或者超小的数使用科学计数法

var x1 = 34.00;     // 带小数点
var x2 = 34;        // 不带小数点
var y = 123e5;      // 12300000
var z = 123e-5;     // 0.00123

字符串类型string

  • 字符串类型用单引号或者双引号包裹
  • 可以使用转译字符’',或者字符模板${变量名},在字符串中引用字符串
  • JS中的字符串是不可变的

JS中数值和字符串相加时,JS将把数值视为字符串:

var x = 911 + "Porsche"; // "911Porsche"
var x = "Porsche" + 911; // "Porsche911"
var x = 911 + 7 + "Porsche";  // "918Porsche"
var x = "Porsche" + 911 + 7; // "Porsche9117"

Js中可以使用模板字符串

let name = "lzy";
let hello = "你好鸭! ${name}";
  • 字符串长度:每个字符串都有length属性,str.length
  • 字符串转换为大写:str.toUpperCase()
  • 字符串转换为小写:str.toLowerCase()
  • 获取某个字符(‘a’)所在位置:str.indexOf(‘a’)
  • 截取字符串:str.substr(1),从第一个字符串截取到最后,str.substr(1,3),截取[1,3)
  • 特殊字符:

在这里插入图片描述

  • 更多字符串方法:
    在这里插入图片描述

数组

1、创建一个数组:

  • 常规方式,新建数组
var myCars=new Array();
myCars[0]="Saab";      
myCars[1]="Volvo";
myCars[2]="BMW";
  • 简洁方式,利用构造函数:
var myCars = new Array("Saab","Volvo","BMW");
  • 字面值方式,直接用中括号初始化赋值:
var myCars=["Saab","Volvo","BMW"];

2、数组常用api

  • 返回数组长度:arr.length
  • 通过元素获取下标:arr.indexof(“Saab”)
  • 截取数组的一部分,返回给一个新数组:arr.slice(left),arr.slice(left, right);
  • 向数组尾部压入或者弹出一个元素,push(),pop()
  • 向数组头部插入或者弹出一个元素,unshift(),shift()
  • 排序:sort()
  • 反转:reverse()
  • 数组合并:arr1.concat(arr2); 注意:concat没有修改数组,会返回一个新的数组。
  • join(),打印拼接数组,使用特定的字符将数组拼接为字符串。
  • 多维数组。

Date

Date(timestamp)可由时间戳返回时间

在这里插入图片描述

Map和Set

创建一个map:

var map = new Map([['Tom', 18], ['jack', 19], ['haha', 80]]);
var name = map.get('Tom');  // 查找
map.set('admin');  // 新增或者修改
map.delete('Tom');  // 删除

Set:无序无重复的集合

set.add(2);
set.delete(1);
console.log(set.has(3));

对象属性

对象声明用花括号:

var car = {name:"fiat", model:500, color:"white"};

也可多行使用:

var person = {
    firstName:"John",
    lastName:"Doe",
    age:50,
    eyeColor:"blue"
};

类型转换

JS中有6种不同的数据类型:

  • string
  • number
  • boolean
  • object
  • function
  • symbol

3种对象类型:

  • Object
  • Data
  • Array

2种不包含任何值的类型

  • undefined
  • null

类型转换常用API:

  • number转为string:

    • 1、使用String():String(x),String(123)
    • 2、使用number方法的toString()
  • 布尔转为字符串

    • false.toString()
    • true.toString()
    • String(false)
    • String(true)
  • 日期转为字符串

    • String(new Data())

函数

函数定义

  • 定义方式1:使用function声明
function abs(x) {
	if (x >= 0) {
	return x
	} else {
		return -x;
	}
}
  • 定义方式2:匿名函数赋值
var abs = function(x) {
	if (x >= 0) {
		return x;
	} else {
		return -x;
	}
}
  • 定义方式3:Function()构造函数
var mul = new Function("a", "b", "return a * b");
var x = mul(4, 3); // 12

函数参数

ES5 中如果函数在调用时未提供隐式参数,参数会默认设置为: undefined

有时这是可以接受的,但是建议最好为参数设置一个默认值:

function myFunction(x, y) {
    if (y === undefined) {
          y = 0;
    } 
}

或者,更简单的方式:

function myFunction(x, y) {
    y = y || 0;
}

ES6 函数可以自带参数
ES6 支持函数带有默认参数,就判断 undefined 和 || 的操作:

function myFunction(x, y = 10) {
    // y is 10 if not passed or undefined
    return x + y;
}
 
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
function myFunction(x, y = 10) {
    // y is 10 if not passed or undefined
    return x + y;
}
 
myFunction(0, 2) // 输出 2
myFunction(5); // 输出 15, y 参数的默认值
arguments对象

arguments 对象包含了函数调用的参数数组。

通过这种方式你可以很方便的找到最大的一个参数的值:

x = findMax(1, 123, 500, 115, 44, 88);
 
function findMax() {
    var i, max = arguments[0];
    
    if(arguments.length < 2) return max;
 
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}

变量的作用域

  • let声明变量,作用于代码块
  • var声明变量,作用于函数内

对象和函数同样也是变量,变量在函数内声明为局部变量,具有局部作用域。

变量在函数外定义,即为全局变量,全局变量具有全局作用域,网页和所有脚本和函数中均可以使用。

var carName = " Volvo";
 
// 此处可调用 carName 变量
function myFunction() {
    // 函数内可调用 carName 变量
}

方法的定义与调用

var person = {
    name: "lzy",
    birth: 1999,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
}

console.log(person.age());
console.log(person.name);
apply

可以使用apply,将方法应用到某个对象上:

方法.apply(对象1,参数)
apply修饰方法,可以将方法中的this指向为apply的第一个参数,对象名,apply的第二的参数是给方法输入参数赋值

function getAge() {
    var now = new Date().getFullYear();
    return now - this.birth;
}

console.log(getAge.apply(person));

注意这里getAge的调用没有(),apply是函数对象的一个方法。

call

call与apply非常像,区别在于当函数有参数时,apply传入的是参数列表数组,而call,直接按顺序填入参数。

JS常用API操作

对象操作

对象增删改查

  • 创建对象 let obj = {}
  • 新增属性 obj.a = 1 、obj[a] = 1
  • 修改属性 obj.a = ‘a’
  • 查询属性 obj.a 、obj[a]
  • 删除属性 delete obj.a

注:对象的key属性也可以是数字,当为数字时,只能使用中括号[]访问。

对象遍历:

for (const key in obj) {
	console.log(key + "=" obj[key]);
}

js深拷贝、浅拷贝

js中对象直接使用=赋值拷贝是浅拷贝,即赋值前后的对象是相关关联的,如果修改其中一个的属性,另外一个属性也会变。
在这里插入图片描述

js实现深拷贝的方式
  • 使用Object.assign(des, src)函数,给目标赋值属性,其中des是目标对象,src是源对象。
let user1 = {};
user1.name = "小米";
user1.age = 18;
user1.sex = "女";

let teacher1 = {};
Object.assign(teacher1, user1);
// 也可合并上边两句为一句
let teacher2 = Object.assign({}, user1);
  • 使用jscon序列化对象再parse的方式也是可以实现深拷贝的。
let teacher3 = JSON.parse(JSON.stringify(user1));

安全访问

?

let a = {};
let b = a?.x;  // 如果a是undefined或者null,b则是undefined,不会报错

??

let a = null;
let b = 1;
let c = a ?? b;  // 如果a为null或者undefined则用b赋值,否则用a赋值
console.log(c);  // 打印c为1

例子:从localStorage拿出一个对象,对象可能为空,此时赋值默认值。

let d = localStorage.getItem('user') ?? {};  // 如果没有user字段,则赋值空

||

||类似??,但是??仅在前边是null或者undefined时,返回右边。
||的含义是,在前边判断逻辑值为false时,返回右边,一般而言,0,null,undefined都是逻辑false。

const x = null;
const y = x ?? "default";
console.log(y); // null

const x = 0;
const y = x ?? 42;
console.log(y); // 0

const x = 0;
const y = x || 42;
console.log(y); // 42

数组操作

1、数组创建:

let arr1 = [];
let arr2 = new Array();

2、数组插入:
数组是一个动态数组,默认是有容量的,里边的内容是undefined。

arr3.push(1);
arr3[2] = 2;

3、数组删除:splice

  • splice(left, right):删除数组[left, right)之间的元素
  • shift():弹出数组头元素
  • pop():弹出数组尾部元素

4、数组截取:slice

  • slice(left, right) :截取[left, right)之间的数组部分,并且返回一个新的数组,对原数组无影响。

5、数组合并:concat
arr1.concat(arr2):将arr1与arr2数组合并,随后返回合并后的新数组,对原数组arr1和arr2并无影响。

在这里插入图片描述
6、数组排序:sort
arr.sort(),默认是按Unicode编码排序,最后使用lambda编写排序规则。

在这里插入图片描述
7、数组反转:reverse
在这里插入图片描述
8、数组过滤:filter

let users = [{name : "lzy", age : 20}, {name : "jhc", age : 24}];
let res1 = [];
user.forEach(aaa => {
	if (aaa.age > 20) {
		res1.push(aaa);
	}
})
console.log(res1);

// 用filter函数可以一句搞定
let res2 = users.filter(aaa => aa.age > 20);
console.log(res2);

9、数组查找:find、findIndex

let res = user.find(v => v.name === "lzy");
let resIdx = user.findIndex(v => v.name === "lzy");

10、数组映射修改:map
令每个名字都以#结尾

let names = user.map(v => "#" + v.name);
console.log(names);

11、数组归类:reduce
reduce()方法最常见的场景就是,计算数组中的每一项的总和。

reduce方法遍历数组每一项,他接收两个参数:

  • 参数1:每次遍历都会调用的函数,函数可以接收4个参数

    • 前一个值
    • 当前值
    • 项目索引
    • 数组对象
  • 参数2:归并基础的初始值

 let arr = [1,2,3,4,5]
 arr.reduce((prev,cur)=>{
      return prev+cur
 })
 // 最后的结果就是累加每一项的值

上面的这段代码,是用来计算数组总和的,reduce()方法中,只传了第一个参数,也就是只传了一个函数,但第二个参数、初始值没有传,当第二个值没有传的时候,第一次循环,prev的值,默认为数组的第一项,而cur的值为数组的第二项,也就是第一次循环,会return 1+2,这个时候,第一次循环返回的结果回传给下一次循环中方法的第一个参数,也就是说、第二次循环方法中prev的值,是第一次循环方法返回的结果.

let arr = [1,2,3,4,5]
arr.reduce((prev,cur)=>{
    return prev+cur
},10)

我们传入一下第二个参数,第一个循环,prev的值为reduce的第二个参数,也就是"归并基础的初始值",而cur的值为数组的第一项,第一项循环会返回10+1。

JS类(未完)

class Runoob {
  constructor(name, url) {
    this.name = name;
    this.url = url;
  }
}
 
let site = new Runoob("菜鸟教程",  "https://www.runoob.com");

类继承

class Site {
  constructor(name) {
    this.sitename = name;
  }
  present() {
    return '我喜欢' + this.sitename;
  }
}
 
class Runoob extends Site {
  constructor(name, age) {
    super(name);
    this.age = age;
  }
  show() {
    return this.present() + ', 它创建了 ' + this.age + ' 年。';
  }
}
 
let noob = new Runoob("菜鸟教程", 5);
document.getElementById("demo").innerHTML = noob.show();

DOM(Document Object Model,文档对象模型)

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model,DOM)。HTML DOM 模型被构造为对象的树:
在这里插入图片描述
通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML:

  • JavaScript 能够改变页面中的所有 HTML 元素
  • JavaScript 能够改变页面中的所有 HTML 属性
  • JavaScript 能够改变页面中的所有 CSS 样式
  • JavaScript 能够对页面中的所有事件做出反应

查找HTML元素

通常,通过 JavaScript,您需要操作 HTML 元素。

为了做到这件事情,您必须首先找到该元素。有三种方法来做这件事:

  • 1、通过 id 找到 HTML 元素
  • 2、通过标签名找到 HTML 元素
  • 3、通过类名找到 HTML 元素
var x=document.getElementById("intro");  // id查找

var x=document.getElementById("main");
var y=x.getElementsByTagName("p");  // 标签名查找

var x=document.getElementsByClassName("intro");  // 通过类名查找

改变HTML元素

1、改变HTML输出流

JavaScript 能够创建动态的 HTML 内容:

今天的日期是: Sat Nov 04 2023 17:25:41 GMT+0800 (中国标准时间)

在 JavaScript 中,document.write() 可用于直接向 HTML 输出流写内容。

<!DOCTYPE html><html>
	<body>
		<script>
		document.write(Date());
		</script>
	</body>
</html>

2、改变HTML内容
修改 HTML 内容的最简单的方法是使用 innerHTML 属性。
如需改变 HTML 元素的内容,请使用这个语法:

document.getElementById(id).innerHTML=新的 HTML

本例改变了 < p >元素的内容:

<html>
<body>
<p id="p1">Hello World!</p>
<script>
document.getElementById("p1").innerHTML="新文本!";
</script>
</body>
</html>

3、改变HTML属性
如需改变 HTML 元素的属性,请使用这个语法:document.getElementById(id).attribute=新属性值
本例改变了 < img > 元素的 src 属性:

<!DOCTYPE html><html>
<body>
<img id="image" src="smiley.gif">
<script>
document.getElementById("image").src="landscape.jpg";
</script>
</body>
</html>

改变CSS

如需改变 HTML 元素的样式,请使用这个语法:

document.getElementById(id).style.property=新样式
下面的例子会改变 < p > 元素的样式:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
 
<p id="p1">Hello World!</p>
<p id="p2">Hello World!</p>
<script>
document.getElementById("p2").style.color="blue";
document.getElementById("p2").style.fontFamily="Arial";
document.getElementById("p2").style.fontSize="larger";
</script>
<p>以上段落通过脚本修改。</p>
</body>
</html>

事件

HTML DOM 使 JavaScript 有能力对 HTML 事件做出反应,常见的事件有:

  • 鼠标点击
  • 页面加载
  • 图像已经加载
  • 鼠标移动到元素
  • 输入字段改变
  • 提交HTML表单
  • 用户触发按键

在本例中,当用户在 < h1 > 元素上点击时,会改变其内容:

<!DOCTYPE html>
<html>
<body>
<h1 onclick="this.innerHTML='触发点击事件!'">点击文本!</h1>
</body>
</html>

本例从事件处理器调用一个函数:

<!DOCTYPE html><html>
<head>
<script>
function changetext(id)
{
    id.innerHTML="点击事件!";
}
</script>
</head>
<body>
<h1 onclick="changetext(this)">点击文本!</h1>
</body>
</html>

也可使用 HTML DOM 来分配事件:

<script>document.getElementById("myBtn").onclick=function(){displayDate()};
	</script>

onload 和 onunload 事件:
onload 和 onunload 事件会在用户进入或离开页面时被触发。

onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。

onload 和 onunload 事件可用于处理 cookie

<body onload="checkCookies()">

onchange 事件:
onchange 事件常结合对输入字段的验证来使用。

下面是一个如何使用 onchange 的例子。当用户改变输入字段的内容时,会调用 upperCase() 函数。

<input type="text" id="fname"
onchange="upperCase()">

onmouseover 和 onmouseout 事件:
onmouseover 和 onmouseout 事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数。

事件冒泡与事件捕获

  • 事件冒泡(Event Bubbling)是指当一个元素触发了某个事件时,该事件会从最具体的元素开始逐级向上传播到较为不具体的元素(也就是从子元素向父元素方向传播),直到传播到文档的根节点为止。这种传播方式就像气泡从水底冒出水面一样,所以叫做事件冒泡。

  • 事件捕获(Event Capturing)是一种处理事件的方式,与事件冒泡相反。事件捕获从文档根节点开始,逐级向下传播到最具体的元素,也就是从父元素向子元素方向传播。

在这里插入图片描述

使用事件冒泡和事件捕获可以实现:

  • 事件委托:可以将事件处理程序绑定到父元素而不是子元素上。当子元素触发该事件时,事件将沿着冒泡路径传递到父元素,由父元素的事件处理程序进行处理。这样可以减少事件处理程序的数量,提高性能和可维护性。
  • 事件拦截:通过在事件处理程序中调用 event.stopPropagation() 方法,可以阻止事件继续传播,从而避免不必要的事件触发和处理。
  • 多个事件处理程序的执行顺序控制:通过在捕获或冒泡阶段注册事件处理程序,并控制其在事件传播路径上的位置,可以控制多个事件处理程序的执行顺序。

事件监听器

1、addEventListener() 方法

  • addEventListener() 方法用于向指定元素添加事件句柄。
  • addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。
  • 你可以向一个元素添加多个事件句柄。你可以向同个元素添加多个同类型的事件句柄,如:两个 “click” 事件。
  • 你可以使用 removeEventListener() 方法来移除事件的监听。

使用语法:

element.addEventListener(event, function, useCapture);
  • 第一个参数是事件的类型 (如 “click” 或 “mousedown”).

  • 第二个参数是事件触发后调用的函数。

  • 第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

例子:

document.getElementById("myBtn").addEventListener("click", displayDate);

element.addEventListener("click", myFunction);

function myFunction() {    
alert ("Hello World!");
}

2、向 Window 对象添加事件句柄
addEventListener() 方法允许你在 HTML DOM 对象添加事件监听, HTML DOM 对象如: HTML 元素, HTML 文档, window 对象。或者其他支持的事件对象如: xmlHttpRequest 对象。

window.addEventListener("resize", function(){
    document.getElementById("demo").innerHTML = sometext;
	});

DOM元素增删改查

appendChild():

<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
 
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
 
var element = document.getElementById("div1");
element.appendChild(para);
</script>

以上的实例我们使用了 appendChild() 方法,它用于添加新元素到尾部。

如果我们需要将新元素添加到开始位置,可以使用 insertBefore() 方法:

<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
 
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
 
var element = document.getElementById("div1");
var child = document.getElementById("p1");
element.insertBefore(para, child);
</script>

removeChild()移除已经存在的元素:

<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
 
<script>
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.removeChild(child);
</script>

替换 HTML 元素 - replaceChild()

<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另外一个段落。</p>
</div>
 
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是一个新的段落。");
para.appendChild(node);
 
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.replaceChild(para, child);
</script>

Collection与NodeList

HTMLCollection 对象类似包含 HTML 元素的一个数组。

  • HTMLCollection 不是一个数组!
  • HTMLCollection 看起来可能是一个数组,但其实不是。
  • 你可以像数组一样,使用索引来获取元素。
  • HTMLCollection 无法使用数组的方法: valueOf(), pop(), push(), 或 join() 。

以下代码获取文档所有的 < p > 元素:

var x = document.getElementsByTagName("p");

NodeList 对象是一个从文档中获取的节点列表 (集合) 。

NodeList 对象类似 HTMLCollection 对象。

一些旧版本浏览器中的方法(如:getElementsByClassName())返回的是 NodeList 对象,而不是 HTMLCollection 对象。

var myNodeList = document.querySelectorAll("p");

BOM(Browser Object Model,浏览器对象模型)

Window

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值