• Vue 学习笔记 [Part 2]


    作者:故事我忘了
    个人微信公众号:程序猿的月光宝盒

    一. 计算属性

    1.1. 计算属性的本质

    • 每个计算属性都包含一个getter和一个setter

    • 一般情况下我们写的都是getter方法

    • 在某些情况下,你也可以提供一个setter方法(不常用)

    • 在需要写setter的时候,代码如下

      图片

    1.2. 计算属性和methods对比

    methods和computed看起来都可以实现我们的功能,

    那么为什么还要多一个计算属性这个东西呢?

    原因:

    • 计算属性在多次使用时, 只会调用一次.

    • 它是有缓存的

      图片

    图片

    〇.ES6补充

    0.1. let/var

    事实上var的设计可以看成JavaScript语言设计上的错误. 但是这种错误多半不能修复和移除, 以为需要向后兼容.

    ​ 大概十年前, Brendan Eich就决定修复这个问题, 于是他添加了一个新的关键字: let.

    ​ 我们可以将let看成更完美的var

    块级作用域

    ​ JS中使用var来声明一个变量时, 变量的作用域主要是和函数的定义有关.

    ​ 针对于其他块定义来说是没有作用域的,比如if/for等,这在我们开发中往往会引起一些问题。

    而在for中使用var时,我们往往需要这样,因为在ES5中 var 只有function有作用域

    图片

    但是在ES6后,用let就简单多了

    图片

    0.2 const的使用

    const这个关键字

    ​ 在很多语言中已经存在, 比如C/C++中, 主要的作用是将某个变量修饰为常量.

    ​ 在JavaScript中也是如此, 使用const修饰的标识符为常量, 不可以再次赋值.

    什么时候使用?

    ​ 修饰的标识符不会被再次赋值时, 就可以使用const来保证数据的安全性.

    0.2.1. 人生建议

    在ES6开发中,优先使用const, 只有需要改变某一个标识符的时候才使用let.

    使用注意点

    const a = 20;
    a = 30; //错误:不可以被修改
    
    const name;//错误:没有赋值
    

    0.3 对象字面量增强写法

    ​ ES6中,对对象字面量进行了很多增强。

    ​ 属性初始化简写和方法的简写:

    图片

    二. 事件监听 v-on

    v-on介绍

    作用:绑定事件监听器

    语法糖:@

    预期:Function | Inline Statement | Object

    参数:event

    2.1. 事件监听基本使用

    这里,我们用一个监听按钮的点击事件,来简单看看v-on的使用

    ​ 下面的代码中,使用了v-on:click="counter++”

    ​ 另外,我们可以将事件指向一个在methods中定义的函数

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <h2>{{counter}}</h2>
      <!--<h2 v-bind:title></h2>-->
      <!--<h2 :title></h2>-->
      <!--<button v-on:click="counter++">+</button>-->
      <!--<button v-on:click="counter&#45;&#45;">-</button>-->
      <!--<button v-on:click="increment">+</button>-->
      <!--<button v-on:click="decrement">-</button>-->
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          counter: 0
        },
        methods: {
          increment() {
            this.counter++
          },
          decrement() {
            this.counter--
          }
        }
      })
    </script>
    
    </body>
    </html>
    

    2.2. 参数问题

    • btnClick
    • btnClick(event)
    • btnClick(abc, event) -> $event 传入
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <!--1.事件调用的方法没有参数-->
      <button @click="btn1Click()">按钮1</button>
      <button @click="btn1Click">按钮1</button>
    
      <!--2.在事件定义时, 写方法时省略了小括号, 但是方法本身是需要一个参数的, 这个时候, Vue会默认将浏览器生产的event事件对象作为参数传入到方法-->
      <!--<button @click="btn2Click(123)">按钮2</button>-->
      <!--<button @click="btn2Click()">按钮2</button>-->
      <button @click="btn2Click">按钮2</button>
    
      <!--3.方法定义时, 我们需要event对象, 同时又需要其他参数-->
      <!-- 在调用方式, 如何手动的获取到浏览器参数的event对象: $event-->
      <button @click="btn3Click(abc, $event)">按钮3</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: '你好啊',
          abc: 123
        },
        methods: {
          btn1Click() {
            console.log("btn1Click");
          },
          btn2Click(event) {
            console.log('--------', event);
          },
          btn3Click(abc, event) {
            console.log('++++++++', abc, event);
          }
        }
      })
    
      // 如果函数需要参数,但是没有传入, 那么函数的形参为undefined
      // function abc(name) {
      //   console.log(name);
      // }
      //
      // abc()
    </script>
    </body>
    </html>
    

    2.3. 修饰符

    • .stop 调用 event.stopPropagation() 停止冒泡

    • .prevent 阻止默认行为

    • .enter 键修饰符,键别名

    • .once 只监听一次

    • .native 监听组件根元素的原生事件

      图片

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <!--1. .stop修饰符的使用,调用 event.stopPropagation() 就是点了之后不显示点div-->
      <div @click="divClick">
        aaaaaaa
        <button @click.stop="btnClick">按钮</button>
      </div>
    
      <!--2. .prevent修饰符的使用 调用 event.preventDefault() 阻止默认行为,以下 是阻止表单默认提交-->
      <br>
      <form action="baidu">
        <input type="submit" value="提交" @click.prevent="submitClick">
      </form>
    
      <!--3. .监听某个键盘的键帽,这里是监听回车按键 把回车按键去掉就都监听了-->
      <input type="text" @keyup.enter="keyUp">
    
      <!--4. .once修饰符的使用 只触发一次回调-->
      <button @click.once="btn2Click">按钮2</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: '你好啊'
        },
        methods: {
          btnClick() {
            console.log("btnClick");
          },
          divClick() {
            console.log("divClick");
          },
          submitClick() {
            console.log('submitClick');
          },
          keyUp() {
            console.log('keyUp');
          },
          btn2Click() {
            console.log('btn2Click');
          }
        }
      })
    </script>
    </body>
    </html>
    

    三. 条件判断

    3.1. v-if/v-else-if/v-else

    ​ 这三个指令与JavaScript的条件语句if、else、else if类似。

    ​ Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件

    简单案例

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <h2 v-if="score>=90">优秀</h2>
      <h2 v-else-if="score>=80">良好</h2>
      <h2 v-else-if="score>=60">及格</h2>
      <h2 v-else>不及格</h2>
      <!--计算属性 直接计算好了返回 不写在dom里-->
      <h1>{{result}}</h1>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          score: 99
        },
        computed: {
          result() {
            let showMessage = '';
            if (this.score >= 90) {
              showMessage = '优秀'
            } else if (this.score >= 80) {
              showMessage = '良好'
            }
            // ...
            return showMessage
          }
        }
      })
    </script>
    </body>
    </html>
    

    v-if的原理:

    ​ v-if后面的条件为false时,对应的元素以及其子元素不会渲染。

    ​ 也就是根本不会有对应的标签出现在DOM中。

    3.2. 登录小案例

    用户再登录时,可以切换使用用户账号登录还是邮箱地址登录。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>模拟登录方式切换</title>
    </head>
    <body>
    <div id="vm">
      <div v-if="showTag">
        <label for="userName">用户账号</label>
        <input id="userName" placeholder="用户账号">
        <!--<input id="userName" placeholder="用户账号" key="name">-->
      </div>
      <div v-else>
        <label for="userMail">用户邮箱</label>
        <input id="userMail" placeholder="用户邮箱">
        <!--<input id="userMail" placeholder="用户邮箱" key="email">-->
      </div>
      <button @click="showTag = !showTag">切换登录方式</button>
    </div>
    </body>
    <script src="../js/vue.js"></script>
    <script>
      const vm = new Vue({
        el:'#vm',
        data:{
          showTag:true
        }
      })
    </script>
    </html>
    

    小问题:

    ​ 如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。

    ​ 但是按道理讲,我们应该切换到另外一个input元素中了。

    ​ 在另一个input元素中,我们并没有输入内容。

    为什么会出现这个问题呢?

    ​ 问题解答:

    ​ 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。

    ​ 在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了。

    ​ 解决方案:

    如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key

    并且我们需要保证key的不同

    3.3. v-show

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <!--v-if: 当条件为false时, 包含v-if指令的元素, 根本就不会存在dom中-->
      <h2 v-if="isShow" id="aaa">{{message}}</h2>
    
      <!--v-show: 当条件为false时, v-show只是给我们的元素添加一个行内样式: display: none-->
      <h2 v-show="isShow" id="bbb">{{message}}</h2>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: '你好啊',
          isShow: true
        }
      })
    </script>
    
    </body>
    </html>
    

    v-show的用法和v-if非常相似,也用于决定一个元素是否渲染:

    v-if和v-show对比

    ​ 相同:

    v-ifv-show都可以决定一个元素是否渲染

    ​ 不同:

    v-if当条件为false时,压根不会有对应的元素在DOM中。

    v-show当条件为false时,仅仅是将元素的display属性设置为none而已。

    开发中如何选择呢?

    ​ 当需要在显示与隐藏之间切换频繁时,使用v-show

    ​ 当只有一次切换时,通过使用v-if

    四. 循环遍历

    4.1. 遍历数组

    当我们有一组数据需要进行渲染时,我们就可以使用v-for来完成。

    ​ v-for的语法类似于JavaScript中的for循环。

    ​ 格式如下:item in items的形式。

    如果在遍历的过程中不需要使用索引值

    ​ v-for="movie in movies"

    ​ 依次从movies中取出movie,并且在元素的内容中,我们可以使用Mustache语法,来使用movie

    如果在遍历的过程中,我们需要拿到元素在数组中的索引值呢?

    ​ 语法格式:v-for=(item, index) in items

    ​ 其中的index就代表了取出的item在原数组的索引值。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <!--1.在遍历的过程中,没有使用索引值(下标值)-->
      <ul>
        <li v-for="item in names">{{item}}</li>
      </ul>
    
      <!--2.在遍历的过程中, 获取索引值-->
      <ul>
        <li v-for="(item, index) in names">
          {{index+1}}.{{item}}
        </li>
      </ul>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          names: ['why', 'kobe', 'james', 'curry']
        }
      })
    </script>
    
    </body>
    </html>
    

    4.2. 遍历对象中的属性

    比如某个对象中存储着你的个人信息,我们希望以列表的形式显示出来。

    • value

    • value, key

    • value, key, index

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Title</title>
      </head>
      <body>
      
      <div id="app">
        <!--1.在遍历对象的过程中, 如果只是获取一个值, 那么获取到的是value-->
        <ul>
          <li v-for="item in info">{{item}}</li>
        </ul>
      
      
        <!--2.获取key和value 格式: (value, key) -->
        <ul>
          <li v-for="(value, key) in info">{{value}}-{{key}}</li>
        </ul>
      
      
        <!--3.获取key和value和index 格式: (value, key, index) -->
        <ul>
          <li v-for="(value, key, index) in info">{{value}}-{{key}}-{{index}}</li>
        </ul>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            info: {
              name: 'kin',
              age: 18,
              height: 1.88
            }
          }
        })
      </script>
      
      </body>
      </html>
      

      官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。

      ​ 为什么需要这个key属性呢(了解)?

      ​ 这个其实和Vue的虚拟DOM的Diff算法有关系。

      ​ 这里我们借用React’s diff algorithm中的一张图来简单说明一下:

      图片

      ​ 当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点

      ​ 我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。

      ​ 即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?

      ​ 所以我们需要使用key来给每个节点做一个唯一标识

      ​ Diff算法就可以正确的识别此节点

      ​ 找到正确的位置区插入新的节点。

      所以一句话,key的作用主要是为了高效的更新虚拟DOM。

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Title</title>
      </head>
      <body>
      
      <div id="app">
        <ul>
          <li v-for="item in letters" :key="item">{{item}}</li>
        </ul>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            letters: ['A', 'B', 'C', 'D', 'E']
          }
        })
      </script>
      
      </body>
      </html>
      

    4.3. 数组哪些方法是响应式的

    push():在最后面添加元素

    unshift():在数组最前面添加元素

    pop():删除数组中的最后一个元素

    shift():删除数组中的第一个元素

    splice():删除,插入,替换

    sort() :排序

    reverse():倒序

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    
    <div id="app">
      <ul>
        <li v-for="item in letters">{{item}}</li>
      </ul>
      <button @click="btnClick">按钮</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          letters: ['a', 'b', 'c', 'd']
        },
        methods: {
          btnClick() {
            // 1.push方法在最后面添加元素
            // this.letters.push('aaa')
            // this.letters.push('aaaa', 'bbbb', 'cccc')
    
            // 2.pop(): 删除数组中的最后一个元素
            // this.letters.pop();
    
            // 3.shift(): 删除数组中的第一个元素
            // this.letters.shift();
    
            // 4.unshift(): 在数组最前面添加元素
            // this.letters.unshift()
            // this.letters.unshift('aaa', 'bbb', 'ccc')
    
            // 5.splice作用: 删除元素/插入元素/替换元素
            // 			第一个参数,index开始位置
            // 删除元素: 第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
            // 替换元素: 第二个参数, 表示我们要替换几个元素, 
            //  		后面的参数:用于替换前面的元素
            // 插入元素: 第二个参数, 传入0, 
            //       	后面的参数:要插入的元素
            // splice(start)
            // splice(start):
            this.letters.splice(1, 3, 'm', 'n', 'l', 'x')
            // this.letters.splice(1, 0, 'x', 'y', 'z')
    
            // 6.sort() 排序
            // this.letters.sort()
    
            // 7.reverse() 倒序
            // this.letters.reverse()
    
            // 注意: 通过索引值修改数组中的元素
            // this.letters[0] = 'bbbbbb';
            // this.letters.splice(0, 1, 'bbbbbb')
            // set(要修改的对象, 索引值, 修改后的值)
            // Vue.set(this.letters, 0, 'bbbbbb')
          }
        }
      })
    
    
      // function sum(num1, num2) {
      //   return num1 + num2
      // }
      //
      // function sum(num1, num2, num3) {
      //   return num1 + num2 + num3
      // }
      // function sum(...num) {
      //   console.log(num);
      // }
      //
      // sum(20, 30, 40, 50, 601, 111, 122, 33)
    
    </script>
    
    </body>
    </html>
    

    五. 书籍购物车案例

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <link rel="stylesheet" href="index.css">
    </head>
    <body>
    <div id="vm">
      <!--判断有没有长度,没有就是空的-->
      <div v-if="books.length">
        <table>
          <thead>
          <tr>
            <th></th>
            <th>书名</th>
            <th>单价</th>
            <th>购买数量</th>
            <th>操作</th>
          </tr>
          </thead>
          <tbody>
          <tr v-for="(item,index) in books">
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <!--showPrice 是过滤器-->
            <td>{{item.price | showPrice}}</td>
            <td>
              <!--v-bind:disabled 条件true时 让按钮失效-->
              <button @click="sub(index)" v-bind:disabled="item.count <= 1">-</button>
              {{item.count}}
              <button @click="add(index)">+</button>
            </td>
            <td>
              <button @click="remove(index)">移除</button>
            </td>
          </tr>
          </tbody>
        </table>
        <h2>总价格:{{totalPrice | showPrice}}</h2>
      </div>
    
      <h2 v-else>购物车为空</h2>
    </div>
    </body>
    <script src="../js/vue.js"></script>
    <script src="main.js"></script>
    </html>
    

    main.js

    const vm = new Vue({
      el:'#vm',
      data:{
        books:[
          {
            id: 1,
            name:'「人間失格」',
            price: 85.42,
            count:1
          },
          {
            id: 2,
            name:'「白夜行」',
            price: 89.00,
            count:1
          },
          {
            id: 3,
            name:'「解忧杂货铺」',
            price: 65.00,
            count:1
          },
          {
            id: 4,
            name:'「天龙八部」',
            price: 185.00,
            count:1
          }
        ]
      },
      methods:{
        sub(index){
          this.books[index].count--
        },
        add(index){
          this.books[index].count++
        },
        remove(index){
          this.books.splice(index,1)
        }
      },
      computed:{
        totalPrice(){
          let totalPrice = 0;
          for (let book of this.books){
            totalPrice += book.price * book.count
          }
          return totalPrice;
        }
      },
      //过滤器
      filters:{
        // 自动把参数传进来
        showPrice(price){
          // .toFixed(2)保留两位小数
          return '¥' + price.toFixed(2)
        }
      }
    });
    

    index.css

    table {
      border: 1px solid #e9e9e9;
      border-collapse: collapse;
      border-spacing: 0;
    }
    th, td {
      padding: 8px 16px;
      border: 1px solid #e9e9e9;
      text-align: left;
    }
    th {
      background-color: #f7f7f7;
      color: #5c6b77;
      font-weight: 600;
    }
    

    点我进演示地址(外服,有点慢)

  • 相关阅读:
    cron表达式详解(转载)
    Swagger 3.0使用教程(转载)
    springboot整合shiro-对密码进行MD5并加盐处理(十五)(转载)
    redis排序
    引用和指针的区别?
    测试策略
    主键、外键的作用,索引的优点与不足?
    您所熟悉的软件测试类型都有哪些?请试着分别比较这些不同的测试类型的区别与联系(如功能测试、性能测试……)
    UI测试测什么
    数据库,数据库管理系统,数据库系统三者的区别和练习?
  • 原文地址:https://www.cnblogs.com/jsccc520/p/12887159.html
Copyright © 2020-2023  润新知