java学习——JavaScript入门


使用<script></script>标签引入,放在 body底部

<script src='index.js'></script>

模板字符串

let firstName = "胡";
let lastName = "雪岩";

let say = `大家好,我姓${firstName},名${lastName}`;

console.log(say);

ECMAScript

基础数据类型
  1. 变量

    • let:可赋值变量声明

    • const:不可改变的常量声明,需要初始化

  2. 数值类型

​ 整数,浮点数,非数值类型:NaN

  1. 类型转换/字符串拼接

    • 隐式转换
      • 数字字符串加数字,数字隐式转换为字符串
      • 数字字符串与数字非加法运算,字符串转换为数字
      • 数字字符串与数字字符串非加法运算,字符串隐式转换为数字
    • 强制类型转换
      • parseInt:将小数,整数,小数转换为整数
      • parseFloat:将小数字符串转换为小数
  2. 运算符

    == : 判断值相同

    === :后者在==基础上判断类型

  3. 数组

    • 声明定义

      • let arr2 = new Array(1,2,'arr');
        
      • [1,2,'arr']
        
    • 操作

      • 增push(从尾加),unshift(从头加)

      • 删pop(从尾删),shift(从头删)

      • 改splice

        //一个参数删除从开始到结束位置的所有元素,并返回删除元素
        //两个参数从第一个参数往后删除第二个参数的个数
        //第三个参数为替换元素
        
        1. 第一个值,整数类型,表示起始位置
        2. 第二个值,整数类型,表示步长(往后选几个元素,1 代表往后选 1 个元素)
        3. 第三个参数,要替换的数组的值
      • 查indexOf

        第一个参数:查询数组中参数的索引没有返回-1

        第二个参数:规定开始查找位置

函数
  1. 自定义函数

    • 用function命令声明

      function 函数名称() {
      	函数体;
      }
      
    • 函数表达式声明(匿名函数)

      let 变量名 = function() {
      	函数体;
      }
      
      let print = () => {
        console.log("JavaScript 真有趣");
      };
      
    • 函数声明提升:采用function命令声明可提升函数声明到顶部

    • 以上两种声明方式区别

      1. 结尾的大括号后是否需要加“;”:
      • function 命令声明:结尾的大括号后不需要加“;”
      • 函数表达式:结尾的大括号后需要加“;”
      1. 有无声明提升:
      • function 命令声明:有提升;
      • 函数表达式:没有提升;
    • 立即执行函数(IIFE)

      (function() {
        console.log("这个函数只执行一次");
      })();
      
  2. 内置函数——计时器

    1. 延时执行 setTimeout():用来指定某个函数或某段代码,在多少毫秒后执行,返回一个表示定时器编号的整数

      let timerId = setTimeout(fun|code, delay);
      
      console.log(1);
      
      /**
       * 第一个参数是代码,注意代码需用引号包裹,否则会立即执行代码
       * 第二个参数是 1000,即 1000ms 后执行 console.log(2)
       */
      setTimeout('console.log(2)', 1000);
      
      /**
       * 第一个参数是匿名函数
       * 第二个参数是 2000,即 2s 后执行 console.log(3)
       */
      setTimeout(function () {
        console.log(3);
      }, 2000);
      
      // 第一个参数是函数名,注意函数名后不要加小括号“()”,否则会立即执行 print4
      setTimeout(print4, 3000);
      
      console.log(5);
      
      function print4() {
        console.log(4);
      }
      
      1;
      5;
      2;
      3;
      4;
      

      倒计时实现(递归)

      // 首先定义计时总秒数,单位 s
      let i = 60;
      
      // 定义变量用来储存定时器的编号
      let timerId;
      
      // 写一个函数,这个函数即每次要执行的代码,能够完成上述的 1、2、3
      function count() {
        console.log(i);
        i--;
        if (i > 0) {
          timerId = setTimeout(count, 1000);
        } else {
          // 清除计时器
          clearTimeout(timerId);
        }
      }
      
      // 首次调用该函数,开始第一次计时
      count();
      
    2. 无限调用setInterval

      let timerId = setInterval(func|code, delay);
      
对象
  1. js的对象就是一组“键值对”集合,创建对象可以通过字面量方法和构造函数法

    // 第一步:创建构造函数
    function People(name, age) {
      this.name = name;
      this.age = age;
    }
    
    // 第二步:通过 new 创建对象实例
    let person = new People('henry', 18);
    console.log(person);
    
  2. 自定义对象的属性操作

    1. 读取属性:点运算符和方括号运算符
    2. 属性的赋值:同上;
    3. 属性查看Object.keys(对象名):返回一个属性名数组
    4. 属性删除:delete 对象.对象属性,增加同赋值
  3. 遍历对象属性

    1. for… in

      let person = {
        name: 'henry',
        age: 18,
      }
      
      for (let key in person) {
        console.log('键名:' + key + ';键值:' + person[key]);
      }
      
    2. Object.keys

      let person = {
        name: 'henry',
        age: 18,
      }
      
      let keys = Object.keys(person);
      
      for (let i = 0; i < keys.length; i++) {
        console.log('键名:' + keys[i] + ';键值:' + person[keys[i]]);
      }
      
  4. 对象的继承:通过构造函数Object()或者“继承创建对象”

    // 字面量
    let o1 = {
      name: 'alice',
    };
    
    // 构造函数
    let o2 = new Object();
    let o3 = new Object();
    
    // 继承
    funtion O4() {
    }; 
    O4.prototype = o1; 
    let o4 = new O4();
    
    1. 原型:继承的上一级对象

    2. 属性是否存在:in

      let person = {
        name: 'henry',
        age: 18,
      };
      
      'name' in person;
      'gender' in person;
      'toString' in person
      
    3. 自身属性是否存在:hasOwnProperty

      let person = {
        name: 'henry',
        age: 18,
      };
      
      person.hasOwnProperty('name');
      person.hasOwnProperty('gender');
      person.hasOwnProperty('toString');
      
    4. Object、JSON、Map

      • JOSN=》JavaScript

        // 一个 JSON 字符串
        const jsonStr =
          '{"sites":[{"name":"Runoob", "url":"www.runoob.com"},{"name":"Google", "url":"www.google.com"},{"name":"Taobao", "url":"www.taobao.com"}]}';
        
        // 转成 JavaScript 对象
        const obj = JSON.parse(jsonStr);
        
      • JavaScript=》JSON

        const jsonStr2 = JSON.stringify(obj)
    5. 内置对象

      1. Math

        Math.E // 常数e。
        Math.LN2 // 2 的自然对数。
        Math.LN10 // 10 的自然对数。
        Math.LOG2E // 以 2 为底的e的对数。
        Math.LOG10E // 以 10 为底的e的对数。
        Math.PI // 常数π。
        Math.SQRT1_2 // 0.5 的平方根。
        Math.SQRT2 // 2 的平方根。
        
        Math.abs() // 绝对值
        Math.ceil() // 向上取整
        Math.floor() // 向下取整
        Math.round() // 四舍五入取整
        Math.max() // 最大值
        Math.min() // 最小值
        Math.pow() // 指数运算
        Math.sqrt() // 平方根
        Math.log() // 自然对数
        Math.exp() // e的指数
        Math.random() // 随机数
        
        1. Storage

        2. sessionStrorage:保存一次会话数据

        3. localStorage:保存数据长期存在

          • 数据存入setItem

            window.localStorage.setItem('key', 'value)
            
          • 读数据getItem

            window.localStorage.getItem('key');
            
          • 清楚缓存

            window.localStorage.clear();
            

          3.String

        let len = 'here is an apple'.length;
        let str = 'here is an apple';
        const index = str.indexOf('an');
        console.log(index);
        // 'here' 之前有一个空格,'apple' 之后有三个空格
        let str = ' here is an apple   ';
        const trimedStr = str.trim();//str不变
        console.log(str.length);
        console.log(trimedStr.length);
        
        • substring(start, end): start —— 要截取的字符串的开始下标 end —— 要截取的字符串的结束下标。
        • substr(start, len): start —— 要截取的字符串的开始下标 len —— 要截取的字符串的长度。
        const splitedStr = 'a|b|c'.split('|');
        console.log(splitedStr);
        
        属性/方法作用
        str.length返回字符串长度
        str.indexOf(sub) 返回子字符串 sub 的开始下标,不存在则返回 -1
        注意:这里的参数 sub 是个字符串变量
        str.trim()字符串前后去空格
        str.substring(s, e) 截取下标从 s 到 e 的子字符串
        注意:这里的参数 s 和 e 是个数字变量
        str.substr(s, len) 截取下标从 s 开始,长度为 len 的子字符串
        注意:这里的参数 s 和 len 是个数字变量
        str.split(pattern) 按规格 pattern 分割字符串
        注意:这里的参数 pattern 是个字符串变量
      2. Array

        1. 连接数组:join()
        let arr = [1, 2, 3, 4];
        
        arr.join(" "); // '1 2 3 4'
        arr.join(" | "); // "1 | 2 | 3 | 4"
        arr.join(); // "1,2,3,4"
        
        1. reverse()
        let arr = ["a", "b", "c"];
        
        arr.reverse(); // ["c", "b", "a"]
        arr; // ["c", "b", "a"]
        
        1. sort()
        let arr = [
          { name: "jenny", age: 18 },
          { name: "tom", age: 10 },
          { name: "mary", age: 40 },
        ];
        
        arr.sort(function (a, b) {
          return a.age - b.age;
        });
        
        console.log(arr);
        
      3. 遍历map/forEach

        1. let arr = [
            { name: "jenny", age: 18 },
            { name: "tom", age: 10 },
            { name: "mary", age: 40 },
          ];
          
          // elem: 数组成员
          // index: 成员下标
          // a: 整个数组
          const handledArr = arr.map(function (elem, index, a) {
            elem.age += 1;
            console.log(elem, index, a);
            return elem.name;
          });
          
          console.log(arr);
          console.log(handledArr);
          
        2. const handledArr = arr.forEach(function (elem, index, a) {
            elem.age += 1;
            console.log(elem, index, a);
            return elem.name;
          });
          
          console.log(handledArr);
          
        属性/方法作用
        arr.join(pattern)按规则 pattern 连接数组,返回字符串
        arr.reverse() 将原数组倒序排列
        arr.sort(func)自定义排序,根据传入的参数函数 func 将数组成员排序
        arr.map(func) 根据传入的参数函数 func 对数组进行遍历操作,返回操作后的数组
        函数有三个参数,依次为:数组成员、对应下标、整个数组
        arr.forEach(func) 根据传入的参数函数 func 对数组进行遍历操作,无返回值
        函数有三个参数,依次为:数组成员、对应下标、整个数组
        1. Date

          1. new Date()不加参数,返回当前时间

            // 传入表示“年月日时分秒”的数字
            let dt1 = new Date(2020, 0, 6, 0, 0, 0);
            console.log(dt1);
            
            // 传入日期字符串
            let dt2 = new Date("2020-1-6");
            console.log(dt2);
            
            // 传入距离国际标准时间的毫秒数
            let dt3 = new Date(1578240000000);
            console.log(dt3);
            
          2. 日期运算

            1. 时间差:毫秒

              // 传入表示“年月日时分秒”的数字
              let dt1 = new Date(2020, 0, 6, 0, 0, 0);
              console.log(dt1);
              
              // 传入日期字符串
              let dt2 = new Date("2020-1-6");
              console.log(dt2);
              
              // 传入距离国际标准时间的毫秒数
              let dt3 = new Date(1578240000000);
              console.log(dt3);
              
          3. 早晚比较:大小于符号

            let dt1 = new Date(2020, 2, 1);
            let dt2 = new Date(2020, 3, 1);
            
            console.log(dt1 > dt2); // false
            console.log(dt1 < dt2); // true
            
          4. 解析日期字符串:Date.parse()

            let dt = Date.parse("2020-1-6");
            console.log(dt); // 1578240000000
            
          5. 时间对象转时间字符串:to方法

            let dt = new Date();
            let dtStr = dt.toJSON();
            
            console.log(dtStr); // 2020-01-03T09:44:18.220Z
            
          6. 获取时间对象的年/月/日:get方法

            let dt = new Date();
            dt.getTime(); // 返回实例距离1970年1月1日00:00:00的毫秒数。
            dt.getDate(); // 返回实例对象对应每个月的几号(从1开始)。
            dt.getDay(); // 返回星期几,星期日为0,星期一为1,以此类推。
            dt.getFullYear(); // 返回四位的年份。
            dt.getMonth(); // 返回月份(0表示1月,11表示12月)。
            dt.getHours(); // 返回小时(0-23)。
            dt.getMilliseconds(); // 返回毫秒(0-999)。
            dt.getMinutes(); // 返回分钟(0-59)。
            dt.getSeconds(); // 返回秒(0-59)。
            
          7. 设置时间对象的年/月/日:set方法

            let dt = new Date();
            dt.setTime(ms); // 设置实例距离1970年1月1日00:00:00的毫秒数。
            dt.setDate(date); // 设置实例对象对应每个月的几号(从1开始)。
            dt.setFullYear(year); // 设置四位的年份。
            dt.setMonth(month); // 设置月份(0表示1月,11表示12月)。
            dt.setHours(hour); // 设置小时(0-23)。
            dt.setMilliseconds(ms); // 设置毫秒(0-999)。
            dt.setMinutes(min); // 设置分钟(0-59)。
            dt.setSeconds(sec); // 设置秒(0-59)。
            

            img

BOM

watermark,image_d2F0ZXJtYXNrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSx3XzEwMA==,t_60,g_se,x_10,y_10

  1. screen 是整个电脑唯一的
  2. navigator 是整个浏览器唯一的,如果有多个浏览器就会有多个 navigator
  3. window 是每个网页唯一的,每个网页都有一个独立的 window
  4. history,location 是每个网页的信息,当然也是网页唯一的
window对象(BOM的默认对象)
Location/History
属性解释
hrefhttps://resource.youkeda.com/wss_test/5dc54e230f101ed7c2256d0d/5e33d104680dca7ebc7a223b/index.html?time=1580454161498href 是整个网页地址
hostnameresource.youkeda.comhostname 是网页域名
hostresource.youkeda.comhost 是网页域名 + 端口信息,在这里端口默认 80 省略了,所有和 hostname 一样
protocolhttpsprotocol 代表协议信息
originhttps://resource.youkeda.comorigin 页面来源的域名的标准形式
pathname/5dc54e230f101ed7c2256d0d/5e33d104680dca7ebc7a223b/index.htmlpathname 包含 url 路径部分
search?time=1580454161498search 表示 URL 参数

watermark,image_d2F0ZXJtYXNrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSx3XzEwMA==,t_60,g_se,x_10,y_10

Location方法:reload()

setTimeout(function () {
  window.location.reload();
}, 3000);

跳转到新的地址

window.location = 'https://www.youkeda.com';

History:将原始网页存到一个栈中,back(),forward();

Navigator/Screen
  1. Navigator属性usesrAgent

DOM

初识DOM

watermark,image_d2F0ZXJtYXNrLnBuZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSx3XzEwMA==,t_60,g_se,x_10,y_10

  1. 树根是 DOCUMENT,也可以称为整个页面文档
  2. 每个 HTML 标签我们称之为 DOM 节点,英文为Node或者ELement
  3. 每个 HTML 标签包裹的子标签,在树上体现为分支,称为儿子节点。比如上图,PH1都是DIV的儿子节点。DIV同样也是BODY的儿子节点。
  4. 儿子节点类推可以得知P,H1BODY孙子节点
  5. 所有P, H1的长辈,我们称为PH1祖先节点
  6. P, H1是亲兄弟,我们称为兄弟节点
访问DOM
  1. 获取DOCUMENTwindow.document

  2. querySelector(‘css选择器’)

  3. 可以利用已经得到的对象进行迭代查询

    let subtitle = document.querySelector('main .core .subtitle');
    console.log(subtitle.querySelector('a'));
    
  4. 选择器全量查询querySelectorAll()//返回一个类数组

DOM属性
  • DOM类别

    • 元素节点
    • 特性节点
    • 文本节点
    • 。。。。
    <!DOCTYPE html>
    <head>
      <meta charset="UTF-8" />
      <title>优课达</title>
    </head>
    <body>
      <div id="test">优课达</div>
      <script src="./index.js"></script>
    </body>
    
    let divDom = document.querySelector('div#test');
    console.log(divDom.nodeType, divDom.nodeName, divDom.nodeValue);
    
    // 获取DIV节点的第一个儿子节点,代表 '优课达' 这个字符串
    let txtDom = divDom.firstChild;
    console.log(txtDom.nodeType, txtDom.nodeName, txtDom.nodeValue);
    
    // 获取DIV节点的id属性
    let attDom = divDom.attributes.id;
    console.log(attDom.nodeType, attDom.nodeName, attDom.nodeValue);
    
    节点nodeTypenodeNamenodeValue类型
    divDom1DIVnull元素节点
    txtDom3#text优课达文本节点
    attDom2idtest特性节点
  • DOM内容

    <!DOCTYPE html>
    <head>
      <meta charset="UTF-8" />
      <title>优课达</title>
    </head>
    <body>
      <div id="test">
        优课达
        <p>youkeda</p>
        <p>学的比别人好一点</p>
      </div>
      <script src="./index.js"></script>
    </body>
    
    let divDom = document.querySelector('div#test');
    console.log(divDom.outerHTML, divDom.innerHTML, divDom.innerText);
    
    属性总结
    outerHTML<div id="test">优课达<p>youkeda</p><p>学的比别人好一点</p></div>整个 DOM 的 HTML 代码
    innerHTML优课达<p>youkeda</p><p>学的比别人好一点</p>DOM 内部 HTML 代码
    innerText优课达DOM 内部纯文本内容
  • DOM亲属

    let divDom = document.querySelector('div#test');
    console.log(divDom.firstChild, divDom.lastChild);
    console.log('-----');
    console.log(divDom.childNodes);
    console.log('-----');
    console.log(divDom.parentNode);
    
    属性总结
    firstChild优课达指定节点的第一个子节点
    lastChild<p>学的比别人好一点</p>指定节点的最后一个子节点
    childNodes优课达<p>youkeda</p><p>学的比别人好一点</p>指定节点的子节点的集合
    parentNode<body><div id="test">优课达<p>youkeda</p><p>学的比别人好一点</p></div><script src="./index.js"></script></body>指定节点在 DOM 树中的父节点
  • DOM样式

    <!DOCTYPE html>
    <head>
      <meta charset="UTF-8" />
      <title>优课达</title>
    </head>
    <body>
      <h1 class="test youkeda" style="color: #FF3300; font-size: 24px;">优课达</h1>
      <script src="./index.js"></script>
    </body>
    
    const h1Dom = document.querySelector('h1');
    console.log(h1Dom.classList);
    console.log(h1Dom.style);
    console.log(h1Dom.style.color)
    
    属性类型总结
    classListDOMTokenList类数组['test', 'youkeda']classList 数组方式存储所有的 class 名称
    styleCSSStyleDeclarationcolor属性为rgb(255, 51, 0)对象或字典的方法存储 CSSStyle
  • DOM数据属性

    <!DOCTYPE html>
    <head>
      <meta charset="UTF-8" />
      <title>优课达</title>
    </head>
    <body>
      <article data-parts="3" data-words="1314" data-category="python">
        ...
      </article>
      <script src="./index.js"></script>
    </body>
    
    const article = document.querySelector('article');
    console.log(article.dataset);//返回Map
    
DOM操作
  • 创建标签节点document.createElement(tagName)、创建文本内容document.createTextNode(string)
  • 添加新节点appendChild(newNode):在所有儿子节点后添加、indertBefore(newNode, referenceNode):在目标儿子节点之前添加
  • 设置样式、属性setAttribute('style', 'width: 100%; height: 100%;');:全量设置属性,dom.style.color = 'xxxx';单独设置属性
  • innerHTML = ‘***’将内部元素全部换成***
DOM事件addEventListener(eventName, callback)
  1. 点击事件
addEventListener("click", function (event) {
  函数体
});

event属性

属性解释
target<h1>优课达-学的比别人好一点</h1>点击事件触发的 DOM 节点,真实响应事件的节点
typeclick事件名称
pageX/pageY92/47鼠标事件触发的页面坐标
  1. 冒泡、捕获、委托

    • 冒泡:因为儿子节点的事件,找到父节点并触发知道html根元素。阻止冒泡

      // ......省略
      likeBtn.addEventListener('click', function(e) {
        // 点击事件
        e.stopPropagation()
      
      // ......省略
      
    • 捕获:事件从根结点开始移动到当前元素被捕获

      dom.addEventListener('click', function() {}, true);
      
    • 委托:用event.target来响应

  2. 移动事件

    鼠标移动事件

    在上一章中,我们在完成京东图片切换的时候,已经接触到鼠标移动事件了,本节课我们详细介绍一下这块知识。

    在第一小节中,我们知道这些鼠标移动事件一共有 5 个如下:

    mouseenter: 指针移到有事件监听的元素内。 mouseleave: 指针移出元素范围外(不冒泡)。 mousemove: 指针在元素内移动时持续触发。 mouseover: 指针移到有事件监听的元素或者它的子元素内。 mouseout: 指针移出元素,或者移到它的子元素上。

    看这个内容还是很混乱,我们把它分类一下

    1. mousemove

    这个是鼠标移动事件,比较简单

    2. mouseenter/mouseleave

    这个是鼠标进入和离开事件,但是仅仅只作用于当前 DOM 节点,不会作用于其后代节点

    3. mouseover/mouseout

    这个也是鼠标进入和离开事件,但和enter/leave不同的是:此事件除了作用于当前 DOM 节点,也会同时作用于其后代节点

    在平时使用中,90%我们都只会使用mouseover/mouseout,这个事件。

  3. 表单元素事件

    1. 获取焦点focus,失去焦点blur

    2. 事件介绍案例
      change当用户提交对元素值的更改时触发; change 事件不一定会对元素值的每次更改触发1. checkbox 值修改以后
      2. select 选择后
      3. input 内容修改并失去焦点
      input只要 value 值修改就会触发
  4. 滚动事件

    window.addEventListener('scroll', function () {
      console.log(window.scrollY);
    });
    

网络请求

  1. GET请求

    fetch(
      'https://www.fastmock.site/mock/b73a1b9229212a9a3749e046b1e70285/f4/f4-11-1-1'
    )
      .then(function (response) {
        return response.json();
      })
      .then(function (myJson) {
        console.log(myJson);
      });
    
  2. POST请求

    // 把JSON数据序列化成字符串
    const data = JSON.stringify({
      username: 'admin',
      password: '123456'
    });
    
    fetch(
      'https://www.fastmock.site/mock/b73a1b9229212a9a3749e046b1e70285/f4/f4-11-4-1',
      {
        method: 'POST',
        body: data,
        headers: {
          'content-type': 'application/json'
        }
      }
    )
      .then(function(response) {
        return response.json();
      })
      .then(function(myJson) {
        console.log(myJson);
      });
    

值修改以后
2. select 选择后
3. input 内容修改并失去焦点


input
只要 value 值修改就会触发


  1. 滚动事件

    window.addEventListener('scroll', function () {
      console.log(window.scrollY);
    });
    

网络请求

  1. GET请求

    fetch(
      'https://www.fastmock.site/mock/b73a1b9229212a9a3749e046b1e70285/f4/f4-11-1-1'
    )
      .then(function (response) {
        return response.json();
      })
      .then(function (myJson) {
        console.log(myJson);
      });
    
  2. POST请求

    // 把JSON数据序列化成字符串
    const data = JSON.stringify({
      username: 'admin',
      password: '123456'
    });
    
    fetch(
      'https://www.fastmock.site/mock/b73a1b9229212a9a3749e046b1e70285/f4/f4-11-4-1',
      {
        method: 'POST',
        body: data,
        headers: {
          'content-type': 'application/json'
        }
      }
    )
      .then(function(response) {
        return response.json();
      })
      .then(function(myJson) {
        console.log(myJson);
      });
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值