谷粒商城-前端基础

1 篇文章 0 订阅

1、技术栈简介

前端技术栈类对比

在这里插入图片描述

一、VSCode使用

下载vsCode用于前端管理系统。在vsCode里安装插件。

  • Auto Close Tag
  • Auto Rename Tag
  • Chinese
  • ESlint
  • HTML CSS Support
  • HTML Snippets
  • JavaScript ES6
  • Live Server
  • open in brower
  • Vetur
  • Vue 2 Snippets

二、ES6

1、简介

ECMAScript6.0 (以下简称ES6,ECMAScript 是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言)是JavaScript 语言的下一代标准,已经在2015 年6月正式发布了,并且从ECMAScript6 开始,开始采用年号来做版本。即ECMAScript 2015,就是ECMAScript6。它的目标,是使得JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。每年一个新版本。

所以,ECMAScript 是浏览器脚本语言的规范,而各种我们熟知的js语言,如JavaScript则是规范的具体实现。

2、ES6新特性

1、let声明变量

  • 创建let.html
  • shift+!快速生成HTML文档
<script>
        // var 声明的变量往往会越狱
        // let 声明的变量有严格局部作用域
        {
            var a = 1;
            let b = 2;
        }
        console.log(a); //1
        console.log(b); //ReferenceError: b is not defined

        //var 可以声明多次
        //let 只能声明一次

        var m = 1
        var m = 2
        let n = 3
        let n = 4
        console.log(m)  //  2
        console.log(n)  //  Identifier 'n' has already been declared

        // var 会变量提升
        // let 不存在变量提升
        console.log(x); //  undefined
        var x = 10;
        console.log(y); //  ReferenceError: y is not defined
        let y = 20;
    </script>

2、const声明常量(只读变量)

<script>
		//let
        //1.声明之后不允许改变
        //2.一旦声明必须初始化,否则会报错
        const a = 1;
        a = 3;  //  Uncaught TypeError: Assignment to constant variable
</script>

3、解构表达式

1、数组解构
<script>

        let arr = [1,2,3];
        
        // let a = arr[0];
        // let b = arr[1];
        // let c = arr[2];

        let [a,b,c] = arr;

        console.log(a,b,c)

    </script>
2、对象解构
<script>

const person = {
            name:"jack",
            age: 21,
            language:['java','js','css']
        }

        // const name = person.name;
        // const age = person.age;
        // const language = person.language;

        //对象结构
        const {name:abc,age,language} = person;

        console.log(abc,age,language);

</script>

4、字符串扩展

1、几个新的API
<script>
		//4、字符串扩展
        let str = "hello.vue"
        console.log(str.startsWith("hello"));   //true
        console.log(str.endsWith("vue"));       //true
        console.log(str.includes("hello"));     //true
        console.log(str.includes("v"));         //true
</script>
2、字符串模板
<script>
		//1、字符串模板
        let ss = `<div>
                    <span>hello world<span>
                </dev>`;
        
        console.log(ss);   


        //2、字符串中调用函数
        function fun(){
            return "这是一个函数"
        }
        
        //3、字符串中插入变量和表达式.变量名写在${}中,${}中可以放入 JavaScript表达式
        let info = `我是${abc},今年${age+10}了,我想说:${fun()}`;
        
        console.log(info);  //我是jack,今年31了,我想说:这是一个函数
</script>

5、函数优化

1、函数参数默认值
<script>
//在ES6之前,我们无法给一个函数参数设置默认值,只能采用变通的写法
        function add(a, b) {
            // 判断b是否为空,为空就给默认值1
            b = b || 1;
            return a + b;
        }
        //传参
        console.log(add(10));

        //现在可以这么写:直接给函数写上默认值,没传就会给默认值
        function add2(a, b = 1) {
            return a + b;
        }
        console.log(add2(10));
</script>
2、不定参数
<script>
//2、不定参数
        function fun(...values) {
            console.log(values.length)
        }
        fun(1, 2)    //2
        fun(1, 2, 3, 4)      //4
</script>
3、箭头函数
<script>
 //3、箭头函数

        //以前声明一个方法
        // var print = function(obj){
        //     console.log(obj)
        // }
        // print("hello"); //hello

        //箭头函数写法
        var print = obj => console.log(obj);
        print("hello")

        var sum = function (a, b) {
            c = a + b;
            return a + c;
        }

        var sum2 = (a, b) => a + b;
        console.log(sum2(1, 2)); //3

        var sum3 = (a, b) => {
            c = a + b;
            return a + c;
        }
        console.log(sum3(1, 2)); //4
</script>
4、实战:箭头函数结合解构表达式
<script>
	const person = {
            name: "jack",
            age: 21,
            language: ['java', 'js', 'css']
        }

        function hello(persion) {
            console.log("hello," + person.name)
        }

        //普通写法
        // var hello2 = (param) => {
        //     console.log("hello,"+param.name)
        // }
        
        //解构写法
        var hello2 = ({name}) => {
            console.log("hello,"+name)
        }
        hello2(person); //hello,jack
</script>

6、对象优化

1、新增的API

ES6给Object拓展了许多新的方法,如:

  • keys(obj):获取对象的所有key形成的数组
  • values(obj):获取对象的所有value形成的数组
  • entries(obj):获取对象的所有key和value 形成的二维数组。格式: [[k1,v1],[k2,v2],...]
  • assign(dest,…src:将多个src.对象的值拷贝到dest中。 (第一 层为深拷贝,第二层为浅
    拷贝)
<script>
	const person = {
            name: "jack",
            age: 21,
            language: ['java', 'js', 'css']
        }

        console.log(Object.keys(person));   //      ["name", "age", "language"]
        console.log(Object.values(person)); //      ["jack", 21, Array(3)]
        console.log(Object.entries(person));    //打印kv  [Array(2), Array(2), Array(2)]


        const target = {a:1};
        const source1 = {b:2};
        const source2 = {c:3};

        //{a:1,b:2,c:3}
        Object.assign(target,source1,source2);
        console.log(target);    //{a: 1, b: 2, c: 3}
</script>
2、声明对象简写
<script>
		//声明对象简写
        const age =23;
        const name ="张三"
        //正常写法
        const person1 = {age:age,name:name};
        //简写
        const persion2 = {age,name};
        console.log(persion2);  //{age: 23, name: "张三"}
</script>
3、对象的函数属性简写
<script>
//3、对象的函数属性简写
        let person3 = {
            name: "jack",
            //以前
            eat: function (food) {
                console.log(this.name + "在吃" + food);
            },
            //箭头函数this不能使用,对象,属性
            eat2: food => console.log(this.name + "在吃" + food),
            eat3: food => console.log(person3.name + "在吃" + food),
            eat4(food) {
                console.log(person3.name + "在吃" + food)
            },
        }
        person3.eat("香蕉");    //jack在吃香蕉

        person3.eat2("苹果");   //在吃苹果
        person3.eat3("苹果");   //jack在吃苹果
        person3.eat4("苹果");   //jack在吃苹果
</script>
4、对象扩展运算符

拓展运算符(…) 用于取出参数对象所有可遍历属性然后拷贝到当前对象

<script>
 //4、对象扩展运算符,拓展运算符(..) 用于取出参数对象所有可遍历属性然后拷贝到当前对象。

        //1、拷贝对象(深拷贝)
        let p1 = { name: "Amy", age: 15 };
        let someone = { ...p1 };
        console.log(someone)    //name: "Amy", age: 15}

        //2、合并对象
        let age1 = { age: 15 }
        let name1 = { name: "Amy" }
        let p2 = { name: "zhangsan" }
        //如果字段名重复。后面会覆盖前面的
        p2 = { ...age1, ...name1 }
        console.log(p2);    //{age: 15, name: "Amy"}
</script>

7、map和reduce

1、map

map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回

<script>

        //数组中新增了map和reduce方法

        //map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回
        let arr = ['1', '20', '-5', '-3']

        // arr = arr.map((item)=>{
        //     return item*2
        // });
        arr = arr.map(item => item * 2)

        console.log(arr);    //(4) [2, 40, -10, -6]

    </script>
2、reduce

语法:
arr.reducelcallback,initialValue])
reduce为数组中的每–个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用reduce 的数组。

callback (执行数组 中每个值的函数,包含四个参数)

  • 1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue) )
  • 2、currentValue (数组 中当前被处理的元素)
  • 3、index ( 当前元素在数组中的索引)
  • 4、array(调用reduce的数组)

initialValue (作为第一 次调用 callback 的第一个参数。 )

<script>

        //reduce()为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素
        //[2, 40, -10, -6]
        let result = arr.reduce((a, b) => {
            console.log("上一次处理后:" + a);
            console.log("当前正在处理:" + b);
            return a + b;
        },100); //100 赋初始值
        console.log(result);   


    </script>

在这里插入图片描述

8、Promise

1、promise特点

ECMAscript 6 原生提供了 Promise 对象。

Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。

Promise 对象有以下两个特点:
1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:

pending: 初始状态,不是成功或失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

在JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现。一旦有一连串的ajax请求a,b,c,d…后面的请求依赖前面的请求结果,就需要层层嵌套。这种缩进和层层嵌套的方式,非常容易造成上下文代码混乱,我们不得不非常小心翼翼处理内层函数与外层函数的数据,一旦内层函数使用了上层函数的变量,这种混乱程度就会加剧…
总之,这种‘层叠上下文的层层嵌套方式,着实增加了神经的紧张程度。

案例:用户登录,并展示该用户的各科成绩。在页面发送两次请求:
1.查询用户,查询成功说明可以登录
2.查询用户成功,查询科目
3.根据科目的查询结果,获取去成绩

分析:此时后台应该提供三个接口,一个提供用户查询接口,一个提供科目的接口,一个提
供各科成绩的接口,为了渲染方便,最好响应json数据。在这里就不编写后台接口了,而
是提供三个json文件,直接提供json数据,模拟后台接口:

  • user.json
{
    "id": 1,
    "name": "zhangsan",
    "password": "123456"
}
  • user-corse_1.json
{
    "id":10,
    "name":"chinese"
}
  • corse_score_10.json
{
    "id": 100,
    "score": 90
}
2、处理异步结果
<script>
// 1、查出当前用户信息
        // 2、按照当前用户的id查出他的课程
        // 3、按照当前课程id查出分数
        $.ajax({
            url: "mock/user.json",
            success(data) {
                console.log("查询用户:", data);
                $.ajax({
                    url: `mock/user_corse_${data.id}.json`,
                    success(data) {
                        console.log("查询到课程:", data);
                        $.ajax({
                            url: `mock/corse_score_${data.id}.json`,
                            success(data) {
                                console.log("查询到分数:", data);
                            },
                            error(error) {
                                console.log("出现异常了:" + error);
                            }
                        });
                    },
                    error(error) {
                        console.log("出现异常了:" + error);
                    }
                });
            },
            error(error) {
                console.log("出现异常了:" + error);
            }
        });
</script>
3、promise改造以前的嵌套方式
<script>
// 1、Promise可以封装异步操作
        let p = new Promise((resolve, reject) => { //传入成功解析,失败拒绝
            //1、异步操作
            $.ajax({
                url: "mock/user.json",
                success: function (data) {
                    console.log("查询用户成功:", data)
                    resolve(data);
                },
                error: function (err) {
                    reject(err);
                }
            });
        });

        p.then((obj) => { //成功以后做什么
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: `mock/user_corse_${obj.id}.json`,
                    success: function (data) {
                        console.log("查询用户课程成功:", data)
                        resolve(data);
                    },
                    error: function (err) {
                        reject(err)
                    }
                });
            })
        }).then((data) => { //成功以后干什么
            console.log("上一步的结果", data)
            $.ajax({
                url: `mock/corse_score_${data.id}.json`,
                success: function (data) {
                    console.log("查询课程得分成功:", data)
                },
                error: function (err) {
                }
            });
        })
</script>
4、优化
  • promise.html
<script>
        function get(url, data) { //自己定义一个方法整合一下
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: url,
                    data: data,
                    success: function (data) {
                        resolve(data);
                    },
                    error: function (err) {
                        reject(err)
                    }
                })
            });
        }

        get("mock/user.json")
            .then((data) => {
                console.log("用户查询成功~~~:", data)
                return get(`mock/user_corse_${data.id}.json`);
            })
            .then((data) => {
                console.log("课程查询成功~~~:", data)
                return get(`mock/corse_score_${data.id}.json`);
            })
            .then((data) => {
                console.log("课程成绩查询成功~~~:", data)
            })
            .catch((err) => { //失败的话catch
                console.log("出现异常", err)
            });

    </script>

在这里插入图片描述

9、模块化

1、什么是模块化

模块化就是把代码进行拆分,方便重复利用。类似于java中的导包,而JS换了个概念,是导模块。

模块功能主要有两个命令构成 exportimport

  • export用于规定模块的对外接口
  • import用于导入其他模块提供的功能
2、export

export不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、对象。

比如定义一个js文件:hello.js,里面有一个对象

// export const util = {
//     sum(a, b) {
//         return a + b;
//     }
// }

// 导出后可以重命名
export default {
    sum(a, b) {
        return a + b;
    }
}
// export {util}

//`export`不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、对象。

  • user.js
var name = "jack"
var age = 21
function add(a,b){
    return a + b;
}
// 导出变量和函数
export {name,age,add}

3、import
  • main.js
import abc from "./hello.js"
import {name,add} from "./user.js"

abc.sum(1,2);
console.log(name);
add(1,3);

4、测试

babel

三、Node.js

四、Vue

1、MVVM思想

  • M:model 包括数据和一些基本操作
  • V:view 视图,页面渲染结果
  • VM:View-model,模型与视图间的双向操作(无需开发人员干涉)

在MVWM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染
到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到
Model中。

而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model
和View之间是如何互相影响的:

  • 只要我们Model发生了改变,View上自然就会表现出来。
  • 当用户修改了View, Model 中的数据也会跟着改变。

把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。
在这里插入图片描述

2、Vue简介

官网: https://cn.vuejs.org/
参考: https://cn.vuejs.org/v2/guide/
Git地址: https://github.com/vuejs

  • 安装

在用 Vue 构建大型应用时推荐使用 NPM 安装[1]。NPM 能很好地和诸如 webpack 或 Browserify 模块打包器配合使用。同时 Vue 也提供配套工具来开发单文件组件。

# 初始化项目
npm init -y
# 最新稳定版
$ npm install vue

3、入门案例

  • index.html
<script src="./node_modules/vue/dist/vue.js"></script>

    <div id="app">
        <h1>{{name}},笑死</h1>
    </div>

    <script>
        let vm = new Vue({
            el: "#app",
            data:{
                name:"张三"
            }
        });
    </script>
  • 测试
    在这里插入图片描述
  • 浏览器修改
    在这里插入图片描述

4、基本语法&插件安装

  • el: “#app”,//绑定元素 div id=“app” // 可以指定恰标签,但是不可以指定body标签
  • data: { //封装数据
    name: “张三”, // 也可以使用{} //表单中可以取出
    num: 1
    },
  • methods:{ //封装方法}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <input type="text" v-model="num">
        v-model实现双向绑定。此处代表输入框和vue里的data绑定
        
        <button v-on:click="num++">点赞</button>
        v-on:click绑定事件,实现自增。
        
        <button v-on:click="cancel">取消</button>
        回调自定义的方法。 此时字符串里代表的函数
        
        <h1> {{name}} ,非常帅,有{{num}}个人为他点赞{{hello()}}</h1>
        先从vue中拿到值填充到dom,input再改变num值,vue实例更新,然后此处也更新
    </div>

    <!-- 导入依赖 -->
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>
        //1、vue声明式渲染
        let vm = new Vue({ //生成vue对象
            el: "#app",//绑定元素 div id="app" // 可以指定恰标签,但是不可以指定body标签
            data: {  //封装数据
                name: "张三",  // 也可以使用{} //表单中可以取出
                num: 1
            },
            methods:{  //封装方法
                cancel(){
                    this.num -- ;
                },
                hello(){
                    return "1"
                }
            }
        });
        // 还可以在html控制台vm.name

        //2、双向绑定,模型变化,视图变化。反之亦然。
        //3、事件处理

        //v-xx:指令

        //1、创建vue实例,关联页面的模板,将自己的数据(data)渲染到关联的模板,响应式的
        //2、指令来简化对dom的一些操作。
        //3、声明方法来做更复杂的操作。methods里面可以封装方法。

    </script>
</body>

</html>

  • 安装Vue 3 Snippets,vue
    实现语法提示
    在这里插入图片描述
  • vue 插件
    在这里插入图片描述

5、指令

1、插值表达式

1)、花括号

格式: {{表达式}}
说明:

  • 该表达式支持JS语法,可以调用js内置函数(必须有返回值)
  • 表达式必须有返回结果。例如1+1,没有结果的表达式不允许使用,如: leta=1+ 1;
  • 可以直接获取Vue实例中定义的数据或函数
	<div id ="app">
        {{msg}} {{1+1}}  {{hello()}}   <!-- <h1>hello</h1> 2 world  -->
        <br/>
        <span v-html="msg"></span>  <!--    hello   -->
        <br/>
        <span v-text="msg"></span>  <!--    <h1>hello</h1>  -->

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script> 
        new Vue({
            el:"#app",
            data:{
                msg:"<h1>hello</h1>"
            },
            methods: {
                hello(){
                    return "world"
                }
            },
        })
    </script>
  • 测试
    在这里插入图片描述
2)、插值闪烁

使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}},

加载完毕后才显示正确数据,我们称为插值闪烁。

我们将网速调慢一些,然后刷新页面,试试看刚才的案例
在这里插入图片描述

  • 测试
    在这里插入图片描述
3)、v-text和v-html
  • v-text
    用于渲染普通文本,
  • v-html
    解析 HTML 代码
	<div id ="app">
        {{msg}} {{1+1}}  {{hello()}}   <!-- <h1>hello</h1> 2 world  -->
        <br/>
        <span v-html="msg"></span>  <!--    hello   -->
        <br/>
        <span v-text="msg"></span>  <!--    <h1>hello</h1>  -->

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script> 
        new Vue({
            el:"#app",
            data:{
                msg:"<h1>hello</h1>"
            },
            methods: {
                hello(){
                    return "world"
                }
            },
        })
    </script>

2、v-bind

给HTML标签的属性绑定,单向绑定
v-bind:,简写为:

<!-- 给HTML标签的属性绑定 -->
    <div id="app">
        <a v-bind:href="link">gogogo</a>

        <!-- class,style  {class名:加上?} -->
        <span v-bind:class="{active:isActive,'text-danger':hasError}"
            v-bind:style="{color: color1,fontSize: size}">你好</span>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>

        let vm = new Vue({
            el: '#app', //element
            data: {
                link: 'http://www.baidu.com',
                isActive: true,
                hasError: true,
                color1: 'red',
                size: '36px'
            }
        })

    </script>

3、v-model

双向绑定

<!-- 表单项,自定义组件 -->
    <div id="app">
        精通的语言
        <input type="checkbox" v-model="language" value="java">java<br />
        <input type="checkbox" v-model="language" value="php">php<br />
        <input type="checkbox" v-model="language" value="python">pyhton<br />
        选中了{{language.join(",")}}
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>

        new Vue({
            el: '#app', //element
            data: {
                language: []
            }
        })

    </script>

在这里插入图片描述

4、v-on:(@)

  • 总demo
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
                
        <!--事件中直接写js片段-->
        <button v-on:click="num++">点赞</button>
        <!--事件指定一个回调函数,必须是Vue实例中定义的函数-->
        <button @click="cancel">取消</button>
        <!--  -->
        <h1>有{{num}}个赞</h1>


        <!-- 事件修饰符 -->
        <div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">
            大div
            <div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">
                小div <br />
                <a href="http://www.baidu.com" @click.prevent.stop="hello">去百度</a>
            </div>
        </div>


 
        <!-- 按键修饰符: -->
        <input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />

        提示:

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                num: 1
            },
            methods:{
                cancel(){
                    this.num--;
                },
                hello(){
                    alert("点击了")
                }
            }
        })
    </script>
</body>

</html>

1、基本语法

事件监听可以使用 v-on 指令

v-on:事件类型="方法",可以简写成@事件类型="方法"

<div id="app">
                
        <!--事件中直接写js片段-->
        <button v-on:click="num++">点赞</button>
        <!--事件指定一个回调函数,必须是Vue实例中定义的函数-->
        <button @click="cancel">取消</button>
        <!--  -->
        <h1>有{{num}}个赞</h1>

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                num: 1
            },
        })
    </script>
2、事件修饰符

事件冒泡:大小div都有单机事件,点了内部div相当于外部div也点击到了。

如果不想点击内部div冒泡到外部div,可以使用.prevent阻止事件冒泡

用法是v-on:事件类型.事件修饰符=“方法”

还可以绑定按键修饰符

v-on:keyup.up=“num+=2” @keyup.down=“num-=2” @click.ctrl=“num=10”

在事件处理程序中调用’event.preventDefault() 或ievent.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。
为了解决这个问题,Vue.js 为’v-on 提供了事件修饰符。修饰符是由点开头的指令后缀来表示的。

  • .stop阻止事件冒泡到父元素
  • `.prevent’ :阻止默认事件发生
  • `.capture’: 使用事件捕获模式
  • `.self’: 只有元素自身触发事件才执行。 (冒泡或捕获的都不执行)
  • ‘.once’:只执行一次
	<!-- 事件修饰符 -->
        <div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">
            大div
            <div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">
                小div <br />
                <a href="http://www.baidu.com" @click.prevent.stop="hello">去百度</a>
            </div>
        </div>
3、按键修饰符
<!-- 按键修饰符: -->
<input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />

全部的按键别名:

  • .enter
  • .tab
  • .delete’(捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left’
  • .right
4、组合按钮
<!-- 按键修饰符: -->
<input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。

  • ctrl
  • alt
  • shift

5、v-for

可以遍历 数组[] 字典{}。对于字典<li v-for="(value, key, index) in object">

  • 1、显示user信息:v-for=“item in items”
    {{index}} = {{user.name}} = {{user.gender}} ={{user.age}}

  • 2、获取数组下标:v-for="(item,index) in items"

  • 3、遍历对象:
    v-for=“value in object”
    v-for="(value,key) in object"
    v-for="(value,key,index) in object"

              对象信息:
              <span v-for="(v,k,i) in user">{{k}}=={{v}}=={{i}};</span>
    
  • 4、遍历的时候都加上:key来区分不同数据,提高vue渲染效率

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <ul>
            <!-- 4、遍历的时候都加上:key来区分不同数据,提高vue渲染效率 ,v-if的优先级比v-for低,所有这里先遍历再判断是否为'女'-->
            <li v-for="(user,index) in users" :key="user.name" v-if="user.gender == ''">	
                <!-- 1、显示user信息:v-for="item in items" -->
               当前索引:{{index}} ==> {{user.name}}  ==>   
                  {{user.gender}} ==>{{user.age}} <br>
                <!-- 2、获取数组下标:v-for="(item,index) in items" -->
                <!-- 3、遍历对象:
                        v-for="value in object"
                        v-for="(value,key) in object"
                        v-for="(value,key,index) in object" 
                -->
                对象信息:
                <span v-for="(v,k,i) in user">{{k}}=={{v}}=={{i}};</span>
                <!-- 4、遍历的时候都加上:key来区分不同数据,提高vue渲染效率 -->
            </li>

            
        </ul>

        <ul>
            <li v-for="(num,index) in nums" :key="index"></li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>         
        let app = new Vue({
            el: "#app",
            data: {
                users: [
                { name: '柳岩', gender: '女', age: 21 },
                { name: '张三', gender: '男', age: 18 },
                { name: '范冰冰', gender: '女', age: 24 },
                { name: '刘亦菲', gender: '女', age: 18 },
                { name: '古力娜扎', gender: '女', age: 25 }
                ],
                nums: [1,2,3,4,4]
            },
        })
    </script>
</body>

</html>

6、v-if&v-show

  • v-if, 顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
  • v-show,当得到结果为true时,所在的元素才会被显示。
  • v-if还能与v-for结合使用,并且优先级v-if低于v-for

区别:show的标签F12一直都在,if的标签会移除,

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 
        v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
        v-show,当得到结果为true时,所在的元素才会被显示。 
    -->
    <div id="app">
        <button v-on:click="show = !show">点我呀</button>
        <!-- 1、使用v-if显示 -->
        <h1 v-if="show">if=看到我....</h1>
        <!-- 2、使用v-show显示 -->
        <h1 v-show="show">show=看到我</h1>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>
        
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                show: true
            }
        })
    </script>

</body>

</html>

  • true时
    在这里插入图片描述
  • false后
    在这里插入图片描述

7、v-else&v-else-if

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <button v-on:click="random=Math.random()">点我呀</button>
        <span>{{random}}</span>

        <h1 v-if="random>=0.75">
            看到我啦? &gt;= 0.75
        </h1>
        <h1 v-else-if="random>=0.5">
            看到我啦? &gt;= 0.5
        </h1>
        <h1 v-else-if="random>=0.2">
            看到我啦? &gt;= 0.2
        </h1>
        <h1 v-else>
            看到我啦? &lt; 0.2
        </h1>

    </div>


    <script src="../node_modules/vue/dist/vue.js"></script>
        
    <script>         
        let app = new Vue({
            el: "#app",
            data: { random: 1 }
        })     
    </script>
</body>

</html>

6、计算属性和侦听器

1、计算属性

什么是计算属性:属性不是具体值,而是通过一个函数计算出来的,随时变化

<div id="app">
        <!-- 某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成 -->
        <ul>
            <li>西游记; 价格:{{xyjPrice}},数量:<input type="number" v-model="xyjNum"> </li>
            <li>水浒传; 价格:{{shzPrice}},数量:<input type="number" v-model="shzNum"> </li>
            <li>总价:{{totalPrice}}</li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        //watch可以让我们监控一个值的变化。从而做出相应的反应。
        new Vue({
            el: "#app",
            data: {
                xyjPrice: 99.98,
                shzPrice: 98.00,
                xyjNum: 1,
                shzNum: 1,
            },
            computed: {
                totalPrice(){
                    return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum
                }
            },
        })
    </script>

在这里插入图片描述

2、监听器

watch可以让我们监控一个值的变化。从而做出相应的反应。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成 -->
        <ul>
            <li>西游记; 价格:{{xyjPrice}},数量:<input type="number" v-model="xyjNum"> </li>
            <li>水浒传; 价格:{{shzPrice}},数量:<input type="number" v-model="shzNum"> </li>
            <li>总价:{{totalPrice}}</li>
            {{msg}}
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        //watch可以让我们监控一个值的变化。从而做出相应的反应。
        new Vue({
            el: "#app",
            data: {
                xyjPrice: 99.98,
                shzPrice: 98.00,
                xyjNum: 1,
                shzNum: 1,
                msg: ""     
            },
            computed: {
                totalPrice(){
                    return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum
                }
            },
            watch: {
                xyjNum: function(newVal,oldVal){
                    if(newVal>=3){
                        this.msg = "库存超出限制";
                        this.xyjNum = 3
                    }else{
                        this.msg = "";
                    }
                }
            },
        })
    </script>

</body>

</html>

3、过滤器

  • 定义filter组件后,管道符后面跟具体过滤器{{user.gender | gFilter}}
  • 过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
  • 全局过滤器,局部过滤器
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 -->
    <div id="app">
        <ul>
            <li v-for="user in userList">
                {{user.id}} ==> {{user.name}} ==> {{user.gender == 1?"男":"女"}} ==>
                {{user.gender | genderFilter}} ==> {{user.gender | gFilter}}
            </li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>

        // 全局过滤器
        Vue.filter("gFilter", function (val) {
            if (val == 1) {
                return "男~~~";
            } else {
                return "女~~~";
            }
        })

        let vm = new Vue({
            el: "#app",
            data: {
                userList: [
                    { id: 1, name: 'jacky', gender: 1 },
                    { id: 2, name: 'peter', gender: 0 }
                ]
            },
            filters: { // 局部过滤器,只可以在当前vue实例中使用
                genderFilter(val) {
                    if (val == 1) {
                        return "男";
                    } else {
                        return "女";
                    }
                }
            }
        })
    </script>
</body>

</html>

7、组件化

在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。

但是如果每个页面都自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同分拆分成立的组件,然后在不同页面就可以共享这些组件,避免重复开发。

在vue里,所有的vue实例都是组件
在这里插入图片描述

  • 组件其实也是一个vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
  • 不同的是组件不会与页面的元素绑定(所以不写el),否则就无法复用了,因此没有el属性。
  • 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
  • data必须是一个函数,不再是一个对象。
  • 全局组件定义完毕,任何vue实例都可以直接在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>
</head>

<body>

    <div id="app">
        <button @click="count++">我被点击了 {{count}} 次</button>

        <counter></counter>
        
        <button-counter></button-counter>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        //全局声明注册一个组件
        Vue.component("counter", {
            template: `<button @click="count++">我被点击了 {{count}} 次</button>`,
            data() {
                return {
                    count: 1
                }
            }
        });

        //2、局部声明一个组件
        const buttonCounter={
            template:`<button @click="count++">我被点击了 {{count}} 次</button>`,
            data () {
                return {
                    count:1
                }
            }
        };

        new Vue({
            el: "#app",
            data: {
                count: 1,
            },
            components:{
                'button-counter':buttonCounter
            }
        });
    </script>
</body>

</html>

1、全局组件

<script>
        //全局声明注册一个组件
        Vue.component("counter", {
            template: `<button @click="count++">我被点击了 {{count}} 次</button>`,
            data() {
                return {
                    count: 1
                }
            }
        });
</script>

2、组件的复用

<div>
	<counter></counter>
</div>
<script>
        //全局声明注册一个组件
        Vue.component("counter", {
            template: `<button @click="count++">我被点击了 {{count}} 次</button>`,
            data() {
                return {
                    count: 1
                }
            }
        });
</script>

3、局部组件

<div id="app">
        <button @click="count++">我被点击了 {{count}} 次</button>

        <counter></counter>
        
        <button-counter></button-counter>
</div>
<script>

        //2、局部声明一个组件
        const buttonCounter={
            template:`<button @click="count++">我被点击了 {{count}} 次</button>`,
            data () {
                return {
                    count:1
                }
            }
        };

        new Vue({
            el: "#app",
            data: {
                count: 1,
            },
            components:{
                'button-counter':buttonCounter
            }
        });
    </script>

8、生命周期和钩子函数

1、声明周期

每个vue实例在被创建时都要经过一系列的初始化过程:创建实例,装载模板、渲染模板等等。vue为生命周期中的每个状态都设置了钩子函数(监听函)。每当vue实列处于不同的生命周期时,对应的函数就会被触发调用。

官网生命周期图示:
在这里插入图片描述

2、钩子函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <span id="num">{{num}}</span>
        <button @click="num++">赞!</button>
        <h2>{{name}},有{{num}}个人点赞</h2>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>
    
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                name: "张三",
                num: 100
            },
            methods: {
                show() {
                    return this.name;
                },
                add() {
                    this.num++;
                }
            },
            beforeCreate() {
                console.log("=========beforeCreate=============");
                console.log("数据模型未加载:" + this.name, this.num);
                console.log("方法未加载:" + this.show());
                console.log("html模板未加载:" + document.getElementById("num"));
            },
            created: function () {
                console.log("=========created=============");
                console.log("数据模型已加载:" + this.name, this.num);
                console.log("方法已加载:" + this.show());
                console.log("html模板已加载:" + document.getElementById("num"));
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            beforeMount() {
                console.log("=========beforeMount=============");
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            mounted() {
                console.log("=========mounted=============");
                console.log("html模板已渲染:" + document.getElementById("num").innerText);
            },
            beforeUpdate() {
                console.log("=========beforeUpdate=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板未更新:" + document.getElementById("num").innerText);
            },
            updated() {
                console.log("=========updated=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板已更新:" + document.getElementById("num").innerText);
            }
        });
    </script>
</body>

</html>

  • 查看
    在这里插入图片描述
  • 点击按钮后
    在这里插入图片描述

9、vue模块化开发

1、npm install webpack -g

  • 全局安装webpack

2、npm install -g @vue/cli-init

  • 全局安装vue脚手架

3、初始化vue项目

  • vue init webpack appname: vue脚手架使用webpack模板初始化一个appname项目

  • 在项目目录下 cmd打开:vue init webpack 项目名

4、启动vue项目

  • 进入项目所在目录
  • npm run dev 运行,访问8080端口

在这里插入图片描述

1、vscode打开

在这里插入图片描述

2、vue项目目录结构:

目录/文件说明
build项目构建(webpack)相关代码
config配置目录,包括端口号等。我们初学可以使用默认的。
导node_modulesnpm 加载的项目依赖模块
src这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件: assets: 放置一些图片,如logo等。components: 目录里面放了一个组件文件,可以不用。App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。main.js: 项目的核心文件。
static静态资源目录,如图片、字体等。
test初始测试目录,可删除
.xxxx文件这些是一些配置文件,包括语法配置,git配置等。
index.html首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
package.json项目配置文件。

3、分析index页面是如何显示的

1、index.html

index.html只有一个<div id="app">

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>demo</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
2、main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,	//路由
  components: { App },
  template: '<App/>'
})
3、App.vue

<router-view/>:路由视图标签是根据url要决定访问的vue

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

4、route路由(index.js)
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

5、component(HelloWorld.vue)

发现这里定义了首页显示的模块
在这里插入图片描述

4、编写一个自己的组件

  • components下新建Hello.vue
<template>
  <div>
    <h1>你好,hello,{{ name }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "张三",
    };
  },
};
</script>

<style>
</style>
  • 编写路由,修改router下的index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Hello from '@/components/Hello'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path:'/hello',
      name:'Hello',
      component:Hello
    }
  ]
})

router-link使用,修改App.vue

<router-link to="/Hello">去hello</router-link>
    <router-link to="/">去首页</router-link>
  • 测试
    在这里插入图片描述
    在这里插入图片描述

10、整合element-ui

官网:https://element.eleme.cn/#/zh-CN/component/installation

  • 安装:npm i element-ui

1、快速上手

在 main.js 中写入以下内容:

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

以上代码便完成了 Element 的引入。需要注意的是,样式文件需要单独引入。

2、使用组件

<template>
  <el-radio v-model="radio" label="1">备选项</el-radio>
  <el-radio v-model="radio" label="2">备选项</el-radio>
</template>

<script>
  export default {
    data () {
      return {
        radio: '1'
      };
    }
  }
</script>

3、搭建一个后台管理系统界面

1、复制Container布局容器
<template>
  <el-container style="height: 500px; border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :default-openeds="['1', '3']">
        <el-submenu index="1">
          <template slot="title"
            ><i class="el-icon-message"></i>导航一</template
          >
          <el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="1-1">选项1</el-menu-item>
            <el-menu-item index="1-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分组2">
            <el-menu-item index="1-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="1-4">
            <template slot="title">选项4</template>
            <el-menu-item index="1-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="2">
          <template slot="title"><i class="el-icon-menu"></i>导航二</template>
          <el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="2-1">选项1</el-menu-item>
            <el-menu-item index="2-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分组2">
            <el-menu-item index="2-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="2-4">
            <template slot="title">选项4</template>
            <el-menu-item index="2-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="3">
          <template slot="title"
            ><i class="el-icon-setting"></i>导航三</template
          >
          <el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="3-1">选项1</el-menu-item>
            <el-menu-item index="3-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分组2">
            <el-menu-item index="3-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="3-4">
            <template slot="title">选项4</template>
            <el-menu-item index="3-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
      </el-menu>
    </el-aside>

    <el-container>
      <el-header style="text-align: right; font-size: 12px">
        <el-dropdown>
          <i class="el-icon-setting" style="margin-right: 15px"></i>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>查看</el-dropdown-item>
            <el-dropdown-item>新增</el-dropdown-item>
            <el-dropdown-item>删除</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
        <span>王小虎</span>
      </el-header>

      <el-main>
      //模块化开发
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

<style>
.el-header {
  background-color: #b3c0d1;
  color: #333;
  line-height: 60px;
}

.el-aside {
  color: #333;
}
</style>

<script>
export default {
  data() {
    const item = {
      date: "2016-05-02",
      name: "王小虎",
      address: "上海市普陀区金沙江路 1518 弄",
    };
    return {
      tableData: Array(20).fill(item),
    };
  },
};
</script>




2、创建MyTable.vue
<template>
  <div class="">
    <el-table :data="tableData">
      <el-table-column prop="date" label="日期" width="140"> </el-table-column>
      <el-table-column prop="name" label="姓名" width="120"> </el-table-column>
      <el-table-column prop="address" label="地址"> </el-table-column>
    </el-table>
  </div>
</template>

data() {
    const item = {
      date: "2016-05-02",
      name: "王小虎",
      address: "上海市普陀区金沙江路 1518 弄",
    };
    return {
      tableData: Array(20).fill(item),
    };
3、编写路由
import MyTable from '@/components/MyTable'

export default new Router({
  routes: [
    {
      path:'/table',
      name:'MyTable',
      component:MyTable
    }
  ]
})
4、修改App.vue
<el-menu :default-openeds="['1', '3']" router="true">
		<el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="/table">用户列表</el-menu-item>
            <el-menu-item index="/hello">Hello</el-menu-item>
          </el-menu-item-group>

点击用户列表,访问路由/table,找到component:MyTable.vue,显示table数据
在这里插入图片描述

五、Babel

六、Webpack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值