前端:ES5和Vue的基本用法

ES6

简介

ECMAScript 6.0 是 JavaScript 语言的下一代标准

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

ES6 新特性

let 声明变量

let 声明的变量有严格局部作用域

       // 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  // Identifier 'n' has already been declared
        console.log(m)  // 2
        console.log(n) 

var 会变量提升, let 不存在变量提升

        console.log(x);  // undefined
        var x = 10;
        console.log(y);//Uncaught ReferenceError: Cannot access 'y' before initialization
        let y = 20; 

const 声明常量(只读变量)

声明之后不允许改变

一但声明必须初始化,否则会报错

        const a = 1;
        a = 3; //Uncaught TypeError: Assignment to constant variable.

解构表达式

数组解构

        let arr = [1,2,3];
        //以前我们想获取其中的值,只能通过角标。
        // let a = arr[0];
        // let b = arr[1];
        // let c = arr[2];

        let [a,b,c] = arr; // a,b,c 将与 arr 中的每个位置对应来取值

        console.log(a,b,c) //1 2 3

对象解构

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


        //对象解构
        //扩展:如果想要将 name 的值赋值给其他变量,可以如下,abc 是新的变量名
        const { name: abc, age, language } = person;
        // 等价于:
        //         const name = person.name;
        //         const age = person.age;
        //         const language = person.language;

        console.log(abc, age, language)//jack 21  ['java', 'js', 'css']

字符串扩展

几个新的 API

  • includes():返回布尔值,表示是否找到了参数字符串。

  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

        let str = "hello.vue";
        console.log(str.startsWith("hello"));//true
        console.log(str.endsWith(".vue"));//true
        console.log(str.includes("e"));//true
        console.log(str.includes("hello"));//true

字符串模板

  • 多行字符串

            let ss = `<div>
                        <span>hello world<span>
                    </div>`;
            console.log(ss);
    
  • 字符串插入变量和表达式。变量名写在 ${} 中,${} 中可以放入JavaScript 表达式。

  • 字符串中调用函数

            const person = {
                name: "jack",
                age: 21,
                language: ['java', 'js', 'css']
            }
            const { name: abc, age, language } = person;
                    function fun() {
                return "这是一个函数"
            }
    
            let info = `我是${abc},今年${age + 10}了, 我想说: ${fun()}`;
            console.log(info);
    

函数优化

函数参数默认值

        //在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(20));

如何理解b = b || 1;这行代码

  • 在JavaScript中,所有的非零数字、非空字符串、非null、非undefined、非false、非NaN、非空对象等都是“真值”(truthy value)

  • 0nullundefinedfalseNaN、空字符串 "" 或空对象 {}都为“假值”(falsy value)

  • ||短路或,一个数为真值时,就返回第一个,否则就返回第二个

        console.log((0||null)); // null
        console.log(("12"||null)); // 12
        console.log((""||0)); // 0
    
  • 所以:b || 1的值,要么是b(b不为假值),要么是1

不定参数

        function fun(...values) {
            console.log(values.length)
        }
        fun(1, 2)      //2
        fun(1, 2, 3, 4)  //4

不定参数用来表示不确定参数个数,形如,…变量名,由…加上一个具名参数标识符组成。

具名参数只能放在参数列表的最后,并且有且只有一个不定参数

箭头函数

        // var print = function (obj) {
        //     console.log(obj);
        // }
        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(11, 12));

        var sum3 = (a, b) => {
            c = a + b;
            return a + c;
        }
        console.log(sum3(10, 20))

箭头函数结合解构表达式

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

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

        //箭头函数+解构
        var hello2 = ({name}) => console.log("hello," +name);
        // hello2(person); ---> hello2({name}=person);
        // 其中:{name}=person 就是取person的name值
        hello2(person);

对象优化

新增的 API

  • keys(obj):获取对象的所有 key 形成的数组

  • values(obj):获取对象的所有 value 形成的数组

  • entries(obj):获取对象的所有 key 和 value 形成的二维数组。格式:[[k1,v1],[k2,v2],...]

  • assign(dest, ...src) :将多个 src 对象的值 拷贝到 dest 中。(==第一层为深拷贝,第二层为浅拷贝==)

        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));//[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}

        target.a=4;
        target.b=5;
        target.c=6;
        console.log(target, source1, source2)

        let personDest={};
        Object.assign(personDest, person);
        console.log(personDest)
        person.age=88;
        person.language[0]='python';
        // 证明第二层是浅拷贝,person.language变了,personDest.language也会变
        console.log(personDest) // {name: 'jack', age: 21, language: ['python', 'js', 'css']}

声明对象简写

        const age = 23
        const name = "张三"
        //传统
        const person1 = { age: age, name: name }

        //ES6:属性名和属性值变量名一样,可以省略
        const person2 = { age, name }
        console.log(person2);

对象的函数属性简写

箭头函数this不能使用,对象.属性

        let person3 = {
            name: "jack",
            // 以前:
            eat: function (food) {
                console.log(this.name + "在吃" + food);
            },

            //箭头函数this不能使用,对象.属性
            eat2: food => console.log(person3.name + "在吃" + food),
            
            eat3(food) {
                console.log(this.name + "在吃" + food);
            }
        }

        person3.eat("香蕉");

        person3.eat2("苹果")

        person3.eat3("橘子");

对象拓展运算符

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

        // 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 } // {age: 15, name: 'Amy'}
        console.log(p2) 
        p3 = {age:88,height:180};
        p2 = {...p3}
        console.log(p2) // {age: 88, height: 180} 之前的值被覆盖了
        p2 = {...name1,...age1,...p3}
        console.log(p2) //  {name: 'Amy', age: 88, height: 180} // 后面覆盖前面

数组的map 和 reduce方法

map

        //map():就是遍历这个数组取执行相关函数
         let arr = ['1', '20', '-5', '3'];
         /** 之前的方式*/
         let arr2 = arr.map((item)=>{
            return item*2
         });
         console.log(arr2) //[2, 40, -10, 6]
         console.log(arr) // ['1', '20', '-5', '3']
         /** 现在的方式*/
         let arr3 = arr.map(item=> item*2);
         console.log(arr3);//[2, 40, -10, 6]
         console.log(arr);//'1', '20', '-5', '3']

reduce

语法:arr.reduce(callback,[initialValue])

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

callback(previousValue, currentValue, index, array)

  • 第一个参数:previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
  • 第二个参数:currentValue (数组中当前被处理的元素)
  • 第三个参数:index (当前元素在数组中的索引)
  • 第四个参数:array (调用 reduce 的数组)

initialValue:初始值,也就是第一次调用时的previousValue

let arr4 = ['1', '20', '-5', '3'];
    let result = arr4.reduce((a,b,c,d)=>{
        let e = a+b;
        console.log("previousValue"+a+", currentValue="+b+", index"+c+", array="+d
                    +", return="+e);
        d[c]='a';// 数组会变,而且会带到下一次循环
        return e;
    },100);
console.log(result)

结果:

Promise

ajax

在 JavaScript 的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现

一连串的 ajax 请求会造成层层嵌套,使得上下文代码混乱,不易维护和管理

案例:用户登录,并展示该用户的各科成绩。在页面发送三次请求:

  • 查询用户,查询成功说明可以登录

  • 查询用户成功,查询科目

  • 根据科目的查询结果,获取去成绩

使用json文件模拟数据:

// es6/mock/user.json
{
    "id": 1,
    "name": "zhangsan",
    "password": "123456"
}
//es6/mock/user_corse_1.json
{
    "id": 10,
    "name": "chinese"
}
//es6/mock/corse_score_10.json
{
    "id": 100,
    "score": 90
}

以下是使用ajax发请求的代码

        $.ajax({
            url: "mock/user.json",
            success(data) {// 1、查出当前用户信息:成功
                console.log("查询用户:", data);
                $.ajax({
                    url: `mock/user_corse_${data.id}.json`,
                    success(data) {//2、按照当前用户的id查出他的课程:成功
                        console.log("查询到课程:", data);
                        $.ajax({
                            url: `mock/corse_score_${data.id}.json`,
                            success(data) {//3、按照当前课程id查出分数:成功
                                console.log("查询到分数:", data);
                            },
                            error(error) {//3、按照当前课程id查出分数:失败
                                console.log("出现异常了:" + error);
                            }
                        });
                    },
                    error(error) {//2、按照当前用户的id查出他的课程:失败
                        console.log("出现异常了:" + error);
                    }
                });
            },
            error(error) { // 1、查出当前用户信息:失败
                console.log("出现异常了:" + error);
            }
        });

promise的语法

const promise = new Promise(function (resolve, reject) {
    // 执行异步操作:发送请求
    if (/* 异步操作成功 */){
        resolve(value);// 调用 resolve,代表 Promise 将返回成功的结果
    } else {
        reject(error);// 调用 reject,代表 Promise 会返回失败结果
    }
});

使用箭头函数可以简写为:

const promise = new Promise((resolve, reject) =>{
    // 执行异步操作:发送请求
    if (/* 异步操作成功 */) {
        resolve(value);// 调用 resolve,代表 Promise 将返回成功的结果
    } else {
        reject(error);// 调用 reject,代表 Promise 会返回失败结果
    }
});

处理异步结果

上面发送完请求(异步操作),根据请求的结果调用then或者catch方法

promise.then(function (value) {
    // 异步执行成功后的回调
}).catch(function (error) {
    // 异步执行失败后的回调
})

Promise 改造以前嵌套方式

        function get(url, data) {
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: url,
                    data: data,
                    success: function (data) {
                        resolve(data); // 处理成功信息
                    },
                    error: function (err) {
                        reject(err) // 处理失败信息
                    }
                })
            });
        }
                // 注意:.then()里面是一个函数,而不是参数
        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)=>{
                console.log("出现异常",err)
            });

模块化

什么是模块化

模块化就是把代码进行拆分,方便重复利用。类似 java 中的导包:要使用一个包,必须先导包。而 JS 中没有包的概念,换来的是 模块

export命令用于规定模块的对外接口。

import命令用于导入其他模块提供的功能。

export

  • 方式一:

    const util = {// 对象
      sum(a,b){
          return a + b;
      }
    }
    export {util};
    
  • 方式二:

    export const util = {
      sum(a,b){
          return a + b;
      }
    }
    
  • 方式三:没有变量名default,由于没有变量名,引入的时候可以随便取名字

    // 无需声明对象的名字
    export default {
      sum(a,b){
          return a + b;
      }
    }
    
  • export不仅可以导出对象,一切 JS 变量都可以导出。比如:基本类型变量、函数、数组、对象。

    var name = "jack"
    var age = 21
    export {name,age}
    

import

  • 方式一:

    // from + 文件的相对路径
    import util from 'hello.js'
    // 调用 util 中的属性
    util.sum(1,2)
    
  • 方式二:批量导入

    import {name, age} from 'user.js'
    console.log(name + " ,
    

    Vue

    安装

    • 直接 script 引入本地 vue 文件。需要通过官网下载 vue 文件。

    • 通过 script 引入 CDN 代理。需要联网,生产环境可以使用这种方式

    • 通过 npm 安装。这种方式也是官网推荐的方式,需要 nodejs 环境。

      # 指定和课件同样的版本 @2.6.10
      xieshaolin@xieshaolindeMacBook-Pro vue3 % cnpm install vue@2.6.10
      ✔ Installed 1 packages
      ✔ Linked 1 latest versions
      ✔ Run 0 scripts
      deprecate vue@2.6.10 Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.
      ✔ All packages installed (1 packages installed from npm registry, used 2s(network 2s), speed 604.25KB/s, json 1(136.27KB), tarball 824.49KB, manifests cache hit 0, etag hit 0 / miss 1)
      

      安装好后会出现如下文件:

      安装好后需要引入:

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

    入门案例

    vue声明式渲染

    <body>
        <div id="app">
          <!-- 页面中的`h2`元素中,我们通过{{name}}的方式,来渲染刚刚定义的 name 属性。 -->
            <h2> {{name}} ,非常帅</h2>
        </div>
    
        <script src="./node_modules/vue/dist/vue.js"></script>
    
        <script>
           //1、vue声明式渲染:首先通过 new Vue()来创建 Vue实例,然后构造函数接收一个对象,对象中有一些属性:
            let vm = new Vue({
                el: "#app",//el:是 element 的缩写,通过 id 选中要渲染的页面元素,本例中是一个 div
                data: {  //data:数据,数据是一个对象,里面有很多属性,都可以渲染到视图中
                    name: "张三",//name:这里我们指定了一个 name 属性
                },
            });
        </script>
    </body>
    

    还可以再控制台修改name的属性

    [!CAUTION]

    在VScode格式化代码:单机右键 —> 格式化代码

双向绑定:v-model

  <body>
    <div id="app">
      <input type="text" v-model="num" />
      <h2>{{name}},非常帅!!!有{{num}}个人为他点赞。</h2>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
      // 创建 vue 实例
      let app = new Vue({
        el: "#app", // el 即 element,该 vue 实例要渲染的页面元素
        data: {
          // 渲染页面需要的数据
          name: "张三",
          num: 5,
        },
      });
    </script>
  </body>

输入框变了,下面的也会变。

事件处理:v-on

  <body>
    <div id="app">
      <input type="text" v-model="num" />
      <button v-on:click="num++">关注</button>
      <h4>{{name}},非常帅!!!有{{num}}个人为他点赞。</h4>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
      // 创建 vue 实例
      let app = new Vue({
        el: "#app", // el 即 element,该 vue 实例要渲染的页面元素
        data: {
          // 渲染页面需要的数据
          name: "张三",
          num: 5,
        },
      });
    </script>

每次点击关注按钮,就会执行num++的命令

这里用v-on指令绑定点击事件,而不是普通的onclick,然后直接操作 num。普通 click 是无法直接操作 num 的

概念

vue实例

//每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:
let app = new Vue({
//在构造函数中传入一个对象,并且在对象中声明各种 Vue 需要的数据和方法,包括:
//- el - data - methods
});

模版或元素

<!-- 每个 Vue 实例都需要关联一段 Html 模板,Vue 会基于此模板进行视图渲染。 -->
<div id="app">
  
</div>

let vm = new Vue({
    el: "#app" // 创建 Vue 实例,关联这个 div
})

数据

<div id="app">
    <input type="text" v-model="name" />
</div>

let vm = new Vue({
  el: "#app",
  /**
    当 Vue 实例被创建时,它会尝试获取在 data 中定义的所有属性,用于视图的渲染,并且监
        视 data 中的属性变化,当 data 发生改变,所有相关的视图都将重新渲染,这就是"响应式"
        系统。
  */
  data: {
      name: "刘德华"
  }
  // 在这个例子中:name 的变化会影响到`input`的值,
  // 而 input 中输入的值,也会导致 vm 中的 name 发生改变
})

方法

<div id="app">
    {{num}}
    <button v-on:click="add">加</button>
</div>

let vm = new Vue({
  el: "#app",
  data: {
      num: 0
  },
  methods: {
    add: function () {
      // this 代表的当前 vue 实例
      this.num++;
    }
  }
})

指令

插值表达式

花括号

格式:{{表达式}}

  • 该表达式支持 JS 语法,可以调用 js 内置函数(必须有返回值)
  • 表达式必须有返回结果,例如 1 + 1。没有结果的表达式不允许使用,如:let a = 1 + 1;

使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}},加载完毕后才显示正确数据,我们称为插值闪烁

v-text和v-html

v-text:将数据输出到元素内部,如果输出的数据有 HTML 代码,会作为普通文本输出

v-html:将数据输出到元素内部,如果输出的数据有 HTML 代码,会被渲染

这两种方法不会出现插值闪烁,当没有数据时,会显示空白或者默认数据。

  <body>
    <div id="app">
      v-text:<span v-text="hello"></span> <br />
      v-html:<span v-html="hello"></span>
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
      let vm = new Vue({
        el: "#app",
        data: {
          hello: "<h1>大家好</h1>",
        },
      });
    </script>
  </body>

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:class="{}"`="{color: color1,fontSize: size}"
        >你好</span
      >
    </div>

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

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

绑定class属性:v-bind:class="{}"

绑定style属性:v-bind:style="{}"

绑定其他属性如href:v-bind:href=""

v-bind的缩写:v-bind:class=:classv-bind:style=:stylev-bind:href=:href

v-bind只是单向绑定:

  • 以下是运行的结果
  • 当我们把color1变成blue的时候,视图也变了

  • 可数当我们修改视图的参数时

  • 数据并没有变化

关于class,当hasError=false的时候,text-danger这个class就会失效

v-text和v-html也是单向绑定

v-model:双向绑定

v-model 的可使用元素有:inputselecttextareacheckboxradiocomponents(Vue 中的自定义组件)

  <body>
    <div id="app">
      <!-- 多个`CheckBox`对应一个 model 时,model 的类型是一个数组 -->
      <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="Swift" />Swift<br />
      <h1>你选择了:{{language.join(',')}}</h1>
      <br />

      <!-- 单个 checkbox 值默认是 boolean 类型 -->
      <input type="checkbox" v-model="boolV" value="boolV" />boolV<br />
      <a>boolV : {{boolV}}</a><br />
      <br />

      <!-- input 对应的值是 input 的 value 值 -->
      <input type="input" v-model="inputValue" /><br />
      <a>inputValue:{{inputValue}}</a><br />
      <br />

      <!-- radio 对应的值是 input 的 value 值 -->
      <input
        type="radio"
        v-model="radioValue"
        value="radioxxxx"
      />radioxxxx11<br />
      <input
        type="radio"
        v-model="radioValue"
        value="radioyyyy"
      />radioyyyy11<br />
      <input
        type="radio"
        v-model="radioValue"
        value="radiozzzz"
      />radiozzzz11<br />
      <a>radioValue:{{radioValue}}</a><br />

      <!-- `text` 和`textarea` 默认对应的 model 是字符串 -->
      <input type="text" v-model="textV" />textV<br />
      <a>textV :{{textV}}</a><br />
      <input type="textarea" v-model="textareaV" />radioyyyy11<br />
      <a>textareaV :{{textareaV}}</a><br />
      <br />
      <!-- `select`单选对应字符串,多选对应也是数组 -->
      单选:<br />
      <select v-model="selectV1">
        <option value="volvo">Volvo</option>
        <option value="saab">Saab</option>
        <option value="mercedes">Mercedes</option>
        <option value="audi">Audi</option></select
      ><br />
      <a>selectV1 :{{selectV1}}</a><br />
      <br />
      多选: <br />
      <br />
      <select v-model="selectV2" multiple>
        <option value="volvo">Volvo</option>
        <option value="saab">Saab</option>
        <option value="mercedes">Mercedes</option>
        <option value="audi">Audi</option></select
      ><br />
      <a>selectV2 :{{selectV2.join(',')}}</a><br />
    </div>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
      let vm = new Vue({
        el: "#app",
        data: {
          language: [],
          inputValue: "",
          radioValue: "",
          boolV: "",
          textV: "",
          textareaV: "",
          selectV1: "",
          selectV2: [],
        },
      });
    </script>
  </body>

[!NOTE]

multiple 属性是一个布尔属性。当存在时,它规定可以一次选择多个选项。

选择多个选项在不同的操作系统和浏览器中有所不同:

  • 对于 Windows:按住 ctrl 键选择多个选项
  • 对于 Mac:按住 command 键选择多个选项

v-on

基本用法

v-on 指令用于给页面元素绑定事件。

语法:v-on:事件名="js 片段或函数名"

  <body>
    <div id="app">
      <!--事件中直接写 js 片段-->
      <button v-on:click="num++">点赞</button>
      <!--事件指定一个回调函数,必须是 Vue 实例中定义的函数-->
       <!--事件绑定可以简写:-on:click="decrement" = @click="decrement" -->
      <button v-on:click="decrement">取消</button>
      <h1>有{{num}}个赞</h1>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript">
      let vm = new Vue({
        el: "#app",
        data: {
          num: 100,
        },
        methods: {
          decrement() {
            this.num--; //要使用 data 中的属性,必须 this.属性名
          },
        },
      });
    </script>
  </body>

事件修饰符

修饰符是由点开头的指令后缀来表示的:

  • .stop :阻止事件冒泡到父元素

    什么是事件冒泡:

      <body>
        <div id="app">
          <div style="border: 1px solid red; padding: 20px" v-on:click="hello">
            大div
            <div style="border: 1px solid blue; padding: 20px" @click="hello">
              小div <br />
              <a href="http://www.baidu.com">去百度</a>
            </div>
          </div>
        </div>
        <script>
          new Vue({
            el: "#app",
            data: {},
            methods: {
              hello() {
                alert("点击了");
              },
            },
          });
        </script>
      </body>
    

    如果点击小div,就等于是点击了大div,这样hello方法就会执行两次。

    加上.stop就可以解决: @click.stop="hello"

            <div style="border: 1px solid blue; padding: 20px" @click.stop="hello">
              小div <br />
              <a href="http://www.baidu.com">去百度</a>
            </div>
    
  • .prevent:阻止默认事件发生

在上面代码中,点击连接会跳转到百度页面,如果我们不想跳转,就可以用它:

 <a href="http://www.baidu.com" @click.prevent>去百度</a>

如果还想在阻止默认行为之后,在作一些其他事情,这个时候可以绑定一个方法:@click.prevent="hello2"

  <body>
    <div id="app">
      <div style="border: 1px solid red; padding: 20px" v-on:click="hello">
        大div
        <div style="border: 1px solid blue; padding: 20px" @click.stop="hello">
          小div <br />
          <a href="http://www.baidu.com" @click.prevent="hello2">去百度</a>
        </div>
      </div>
    </div>
    <script>
      new Vue({
        el: "#app",
        data: {},
        methods: {
          hello() {
            alert("点击了");
          },
          hello2() {
            alert("~~~~~~");
          },
        },
      });
    </script>
  </body>

可以如果我们点击连接,其实会执行hello和hello2方法,出现了事件冒泡。可以再次用.stop解决:@click.prevent.stop="hello2"

 <a href="http://www.baidu.com" @click.prevent.stop="hello2">去百度</a>
  • .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="hello2">去百度</a>
        </div>
      </div>

v-on:click.once="hello"这样第二次点击大div的时候,就不会再执行hello方法

按键修饰符

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

    <script type="text/javascript">
      let app = new Vue({
        el: "#app",
        data: {
          num: 0,
        },
      });
    </script>
  </body>

v-on:keyup.up="num+=2":表示一次上键,num加2

@keyup.down="num-=2":是v-on:keyup.down="num-=2"的缩写,表示按一次下键,num减2

@click.meta="num=10":这是一个组合按钮。需要按住meta(windows中为window键,mac中为command键),然后点击,就会使num等于10

实际上的语法是:<input v-on:keyup.13="submit">,这里的13是keyCode。但是记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

别名 按键
.delete delete(删除)/BackSpace(退格)
.tab Tab
.enter Enter(回车)
.esc Esc(退出)
.space Space(空格键)
.left Left(左箭头)
.up Up(上箭头)
.right Right(右箭头)
.down Down(下箭头)
.ctrl Ctrl(和mac没有找到对应)
.alt Alt (对应mac的option)
.shift Shift
.meta windows中为window键,mac中为command键

v-for

遍历数组

    <div id="app">
      <ul>
        <li v-for="user in users">
          {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
      </ul>
    </div>
    <script type="text/javascript">
      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 },
          ],
        },
      });
    </script>

语法:v-for=”item in items”

  • items:要遍历的数组,需要在 vue 的 data 中定义好。
  • item:迭代得到的当前正在遍历的元素

数组角标

    <div id="app">
      <ul>
        <li v-for="(user, index) in users">
          {{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
      </ul>
    </div>

语法:v-for=”(item,index) in items”

  • items:要迭代的数组
  • item:迭代得到的数组元素别名
  • index:迭代到的当前元素索引,从 0 开始。

遍历对象

    <div id="app">
      <ul>
        <li v-for="(value, key, index) in user">
          {{index + 1}}. {{key}} - {{value}}
        </li>
      </ul>
    </div>
    <script type="text/javascript">
      let vm = new Vue({
        el: "#app",
        data: {
          user: { name: "张三", gender: "男", age: 18 },
        },
      });
    </script>

语法:v-for=”value in object” && v-for=”(value,key) in object” &&v-for=”(value,key,index) in object”

  • 1 个参数时,得到的是对象的属性值
  • 2 个参数时,第一个是属性值,第二个是属性名
  • 3 个参数时,第三个是索引,从 0 开始

Key

用来标识每一个元素的唯一特征,这样 Vue 可以有效的提高渲染的效率

<ul>
    <li v-for="(item,index) in items" :key=”index”></li>
</ul>
<ul>
    <li v-for="item in items" :key=”item.id”></li>
</ul>

这里的:key就是唯一标识,加上这个配置可以提高渲染效率。无论是数组还是对象,都采用唯一标识index,作为key的值。

v-if 和 v-show

v-if:当得到结果为 true 时,所在的元素才会被渲染。

v-show:当得到结果为 true 时,所在的元素才会被显示。

语法:v-if="布尔表达式"v-show="布尔表达式"

    <div id="app">
      <button v-on:click="show = !show">点我呀</button>
      <br />
      <h1 v-if="show">看到我啦?!if</h1>
      <h1 v-show="show">看到我啦!show</h1>
    </div>
    <script type="text/javascript">
      let app = new Vue({
        el: "#app",
        data: {
          show: true,
        },
      });
    </script>

v-for结合,筛选出女生来

  <body>
    <div id="app">
      <ul>
        <li v-for="(user, index) in users" v-if="user.gender == '女'">
          {{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
        </li>
      </ul>
    </div>
    <script type="text/javascript">
      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 },
          ],
        },
      });
    </script>
  </body>

v-elsev-else-if结合,作条件判断

  <body>
    <div id="app">
      <button v-on:click="random=Math.random()">点我呀</button><br /><br /><br />
      <span>random={{random}}</span>
      <h1 v-if="random >= 0.75">看到我啦?!v-if >= 0.75</h1>
      <h1 v-else-if="random > 0.5">看到我啦?!v-else-if > 0.5</h1>
      <h1 v-else-if="random > 0.25">看到我啦?!v-else-if > 0.25</h1>
      <h1 v-else>看到我啦?!v-else</h1>
    </div>

    <script type="text/javascript">
      let app = new Vue({
        el: "#app",
        data: {
          random: 1,
        },
      });
    </script>
  </body>

计算属性和侦听器

  <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>
      //watch可以让我们监控一个值的变化。从而做出相应的反应。
      new Vue({
        el: "#app",
        data: {
          xyjPrice: 99.98,
          shzPrice: 98.0,
          xyjNum: 1,
          shzNum: 1,
          msg: "",
        },
        // 计算属性
        computed: {
          totalPrice() { // totalPrice的值是基于 其他操作之后 得出的值 来计算的;而且是实时计算
            return this.xyjPrice * this.xyjNum + this.shzPrice * this.shzNum;
          },
        },
        watch: { // 监听器
          xyjNum(newVal, oldVal) { // 监听xyjNum这个变量,这个变量发生变化之后,会执行后面的函数
            if (newVal >= 3) {
              this.msg = "库存超出限制";
              this.xyjNum = 3;
            } else {
              this.msg = "";
            }
          },
        },
      });
    </script>
  </body>

过滤器

<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>
    <!--  
        每个过滤器要使用三元运算符来赋值男女:user.gender == 1?"男":"女" 
        有过滤器后,使用 通道符 `|`  {{user.gender | genderFilter}}
        每一个元素都会执行genderFilter方法和gFilter方法
        传入的值:user.gender
    -->
    <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: {
                //// filters 定义局部过滤器,只可以在当前vue实例中使用
                genderFilter(val) {
                    if (val == 1) {
                        return "男";
                    } else {
                        return "女";
                    }
                }
            }
        })
    </script>
</body>

user.gender == 1?"男":"女"这段代码改变了user.gender的值,有代码侵入。

但是过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本。

过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值v-bind表达式

组件化

  <body>
    <div id="app">
      <button v-on:click="count++">我被点击了 {{count}} 次</button> <br />
      <br />
      全局组件:<counter></counter><br />
      <br />
      局部组件:<jb></jb><br />
    </div>

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

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

      new Vue({
        el: "#app",
        data: {
          count: 1,
        },
        // 然后在 Vue 中使用局部组件
        components: {
          "jb": buttonCounter,
        },
        /**
        components 就是当前 vue 对象子组件集合。
        - 其 key 就是子组件名称
        - 其值就是组件对象名
        */
      });
    </script>
  </body>

组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函数等

不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性。

但是组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板

全局组件定义完毕,任何 vue 实例都可以直接在 HTML 中通过组件名称来使用组件了

data 必须是一个函数,不再是一个对象

定义好的组件,可以任意复用多次

一旦组件全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。因此,对于一些并不频繁使用的组件,我们会采用局部注册。

局部组件效果与全局注册是类似的,不同的是,局部组件只能在当前的 Vue 实例中使用

生命周期钩子函数

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

    <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>

点击按钮之后,会先后执行beforeUpdateupdated

vue 模块化开发

安装vue项目

全局安装webpack

npm install webpack -g

全局安装 vue 脚手架

npm install -g @vue/cli-init

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

vue init webpack vue-test

问题:How to fix “zsh: command not found: vue”? – Zsh

  1. Uninstall the existing vue CLI globally using these commands:
    • sudo npm uninstall --global vue-cli
    • sudo npm uninstall --global @vue/cli
  2. Install the latest version of vue CLI globally:
    • sudo npm install --global @vue/cli@latest
  3. Ensure that the vue command is now recognized by running:
    • vue --version

启动项目:npm start = npm run dev

了解vue项目结构

项目结构如下:

项目运行的大致流程:

  1. 主入口页面:index.html,里面的内容非常简单:

      <body>
        <div id="app"></div>
        <!-- built files will be auto injected -->
      </body>
    
  2. 主程序文件:src/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', // 挂载 index里面的div页面
      router, // 路由,这里是简写,完整写法是 router:router
      // 使用App这个组件,组件用于页面,这里是简写,全写是 App:App。在Vue实例中,是一个局部组件。组件来源:src/App.vue
      components: { App }, 
      template: '<App/>' // 表示使用App组件
    })
    
  3. App组件:src/App.vue

    <!-- template: 决定页面如何展示,怎么展示 -->
    <template>
      <div id="app">
        <!-- 引入一张图片:src/assets/logo.png -->
        <img src="./assets/logo.png">
        <!-- 路由视图:意思是页面上方是一张图片,而页面下方显示什么,是有路径决定的 -->
        <router-view/>
      </div>
    </template>
    
    <!-- script代码:数据的运算等。如data和method -->
    <script>
    export default {
      name: 'App' // 定义这个组件的名字加 App。在main.js中:template: '<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>
    

    目前页面是这样:

    我们目前的访问路径是这样:http://localhost:8080/#/

    在main.js中的router, 配置,决定了访问路径和展示内容的关系

  4. 路由内容:src/router/index.js

    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'//引入HelloWorld组件。这里的@表示src目录
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {//意思是:http://localhost:8080/ 这个路径访问,就展示HelloWorld这个组件
          path: '/',
          name: 'HelloWorld',
          component: HelloWorld
        }
      ]
    })
    
  5. HelloWorld组件:src/components/HelloWorld.vue

    <template>
      <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>Essential Links</h2>
        <ul>
          <li>
            <a
              href="https://vuejs.org"
              target="_blank"
            >
              Core Docs
            </a>
          </li>
          <li>
            <a
              href="https://forum.vuejs.org"
              target="_blank"
            >
              Forum
            </a>
          </li>
          <li>
            <a
              href="https://chat.vuejs.org"
              target="_blank"
            >
              Community Chat
            </a>
          </li>
          <li>
            <a
              href="https://twitter.com/vuejs"
              target="_blank"
            >
              Twitter
            </a>
          </li>
          <br>
          <li>
            <a
              href="http://vuejs-templates.github.io/webpack/"
              target="_blank"
            >
              Docs for This Template
            </a>
          </li>
        </ul>
        <h2>Ecosystem</h2>
        <ul>
          <li>
            <a
              href="http://router.vuejs.org/"
              target="_blank"
            >
              vue-router
            </a>
          </li>
          <li>
            <a
              href="http://vuex.vuejs.org/"
              target="_blank"
            >
              vuex
            </a>
          </li>
          <li>
            <a
              href="http://vue-loader.vuejs.org/"
              target="_blank"
            >
              vue-loader
            </a>
          </li>
          <li>
            <a
              href="https://github.com/vuejs/awesome-vue"
              target="_blank"
            >
              awesome-vue
            </a>
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      name: 'HelloWorld',
      data () {
        return {
          msg: 'Welcome to Your Vue.js App'
        }
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
    h1, h2 {
      font-weight: normal;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      display: inline-block;
      margin: 0 10px;
    }
    a {
      color: #42b983;
    }
    </style>
    

导入 element-ui 快速开发

element-ui官网

  1. 安装element-ui

    npm i element-ui -S
    
  2. 引入 Element

    // 引入
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    // 使用
    Vue.use(ElementUI) // 没有这段代码:‘ElementUI‘ is defined but never used no-unused-vars
    
  3. 根据文档操作编写即可


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com

×

喜欢就点赞,疼爱就打赏