Part2-常用指令

一、属性绑定(掌握)

1、v-bind介绍

前面我们都是通过指令来将值插入到我们的标签内容中,但除了内容外,我们还需要动态绑定某些属性,比如:a标签中的href属性,img标签中的src属性;这个时候我们就可以使用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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <img :src="src"/>
    <a :href="href">Vue官网</a>
  </div>
</body>
<script>
  new Vue({
    el: '#app',
    data: {
      src: 'https://vuejs.org/images/logo.png',
      href: 'https://vuejs.org/'
    }
  })
</script>
</html>

注意点

v-bindv-on 一样也有简写的方式,v-bind:src="" 可以简写成 :src=""

2、v-bind绑定class

很多时候,我们希望能动态切换class,选中字体颜色变红,初始状态字体为黑色;绑定class有两种方式:对象语法,数组语法。

<!DOCTYPE html>
<html>
<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></title>
    <style>
        .current{
            color: blue;
        }
        .italicFont{
            font-style: italic;
        }
        .line{
            text-decoration: underline;
        }
    </style>
</head>
<body>
<div id="app">
    <ul>
        <li>普通一行文字</li>
        <li class="current">添加了current类名的文字</li>
        <li v-bind:class="{'current': isCurrent}">对象格式,由isCurrent判断是否添加current类名</li>
        <li class="line" :class="{'current': isCurrent, 'italicFont': isItalic}">多个类名</li>
        <li :class="isCurrent ? 'current line' : 'line'">三元运算符决定类名</li>
        <li :class="['current', 'line']">数组形式的多类名</li>
        <li :class="getClass()">通过方法来返回类名</li>
    </ul>
</div>
</body>
</html>
<script src="./lib/vue.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        isCurrent: true,
        isItalic: true
    },
    methods: {
        getClass(){
            return {
                'current': this.isCurrent
            }
        }
    }
})
</script>

3、v-bind绑定style

我们可以利用v-bind:style来绑定一个内嵌样式。

注意:

  1. 我们可以使用驼峰式语法:比如font-size ---> fontSize

  2. 或短横线分隔 font-size

绑定class有两种方式:

  1. 对象语法

  2. 数组语法

<!DOCTYPE html>
<html>
<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></title>
</head>
<body>
<div id="app">
    <ul>
        <li style="background: skyblue;">通过style标签属性写的样式</li>
        <li :style="{background: 'pink',fontStyle: 'italic'}">通过v-bind来绑定样式</li>
        <li :style="{background: bgColor,color: fontColor}">数据来自data</li>
        <li :style="[colorStyle, bgStyle]">数组形式</li>
        <li :style="getStyle()">方法形式</li>
    </ul>
</div>
</body>
</html>
<script src="./lib/vue.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        bgColor: 'orange',
        fontColor: '#cfc',
        colorStyle: {color: 'pink'},
        bgStyle: {background: 'skyblue'}
    },
    methods: {
        getStyle(){
            return [this.colorStyle, this.bgStyle]
        }
    }
})
</script>

二、循环遍历v-for、key(掌握)

v-for格式:item in items形式

<!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>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <div>
            <input type="text" v-model="inputVal"/>
            <button @click="add">添加</button>
        </div>
        
        <ul>
            <li v-for="(item,index) in arr" :key="index">
                <input type="checkbox"/>
                {{item.name}}
            </li>
        </ul>
    </div>
</body>
<script>
    new Vue({
        el: '#app',
        data: {
            arr: [
                {id: 1, name: 'Vue'},
                {id: 2, name: 'React'},
                {id: 3, name: 'Angular'}
            ],
            inputVal: ''
        },
        methods: {
            add() {
                this.arr.unshift({id: this.arr.length + 1, name: this.inputVal})
            }
        }
    })
</script>
</html>

组件的key属性

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

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

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

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

  1. 在B和C之间加一个F,Diff算法默认执行起来时这样的;即把C更新成F,D更新成C,E更新成D,最后再插入一个新的E,这样的效率也太低了。

当我们使用key来为每一个节点做唯一标识

  1. Diff算法会以key作为标识来识别此节点,找到正确的位置区插入新的节点,所以key的作用是为了高效的更新虚拟DOM

三、计算属性(掌握)

https://cn.vuejs.org/v2/guide/computed.html

我们知道,在模板中可以直接通过插值语法显示一些data中的数据。但是某些情况下,我们可能需要对数据进行转化后再显示,或者需要将多个数据结合起来进行显示

例子

<!DOCTYPE html>
<html>
<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></title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="item in arr" :key="item.id">
            书名:{{item.name}} -- 价格:{{item.price}}
        </li>
    </ul>
    <h4>总价:{{totalPrice}}</h4>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        arr: [
            {id: "b01", name: "海底两万里", price: 23},
            {id: "b02", name: "西游记", price: 24},
            {id: "b03", name: "红楼梦", price: 32}
        ]
    },
    computed: {
        totalPrice(){
            let sum = 0;
            this.arr.map(val=>{
                sum+=val.price;
            })
            return "¥ " + sum.toFixed(2) + " 元";
        }
    }
})
</script>

为什么会有这样的一个属性呢,用methods都可以实现我们的功能,为什么多了这样一个计算属性的东西呢?

computed与methods的区别

1、computed是属性调用,methods是方法调用

2、computed有缓存功能,多次使用时,该属性只会触发一次调用,而methods是使用一次就触发一次

<!DOCTYPE html>
<html>
<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></title>
</head>
<body>
<div id="app">
    <ul>
        <li v-for="item in arr" :key="item.id">
            书名:{{item.name}} -- 价格:{{item.price}}
        </li>
    </ul>
    <h4>computed计算总结:{{totalPrice1}}</h4>
    <h4>computed计算总结:{{totalPrice1}}</h4>
    <h4>computed计算总结:{{totalPrice1}}</h4>
    <hr>
    <h4>methods计算总价:{{totalPrice()}}</h4>
    <h4>methods计算总价:{{totalPrice()}}</h4>
    <h4>methods计算总价:{{totalPrice()}}</h4>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        arr: [
            {id: "b01", name: "海底两万里", price: 23},
            {id: "b02", name: "西游记", price: 24},
            {id: "b03", name: "红楼梦", price: 32}
        ]
    },
    computed: {
        totalPrice1(){
            let sum = 0;
            this.arr.map(val=>{
                sum+=val.price;
            })
            console.log('计算属性: '+sum)
            return "¥ " + sum.toFixed(2) + " 元";
        }
    },
    methods: {
        totalPrice(){
            let sum = 0;
            this.arr.map(val=>{
                sum+=val.price;
            })
            console.log('methods方法: '+sum)
            return "¥ " + sum.toFixed(2) + " 元";
        }
    }
})
</script>

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

<!DOCTYPE html>
<html>
<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></title>
</head>
<body>
<div id="app">
    <h3>名:{{firstName}}</h3>
    <h3>姓:{{lastName}}</h3>
    <h3>姓名:{{fullName}}</h3>
</div>
</body>
</html>
<script src="./lib/vue.js"></script>
<script>
var vm = new Vue({
    el: "#app",
    data: {
        firstName: 'Michael',
        lastName: 'Jackson'
    },
    computed: {
        fullName: {
            get(){
                return this.firstName + ' ' + this.lastName;
            },
            set(val){
                const fullName = val.split(' ');
                this.firstName = fullName[0];
                this.lastName = fullName[1];
            }
        }
    },
})
</script>

四、v-model原理(掌握)

v-model 其实是个语法糖,它背后本质上包含了两个操作:

  1. v-bind 绑定input元素的value属性

  2. v-on 指令绑定input元素的input事件

<input type="text" v-model="msg"/>
<!-- 等同于 -->
<input type="text" v-bind:value="msg" v-on:input="msg = $event.target.value"/>

下拉选择框

<body>
  <div id="app">
    <select v-model="mySelect">
      <option value="orange">橙子</option>
      <option value="apple">苹果</option>
      <option value="banana">香蕉</option>
    </select>
  </div>
</body>
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      mySelect: 'banana'
    }
  })
</script>

五、数组操作(掌握)

常用操作: push(返回数组长度)、unshift(返回数组长度)、shift(返回删除的值)、pop(返回删除的值)、slice(返回新的数组)、splice、concat(返回新数组)

新增迭代方法:forEach(没有返回值)、map、filter、reduce

六、自定义过滤器(掌握)

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 ( 后者从 2.1.0+ 开始支持 )。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:

格式化价格:

<!DOCTYPE html>
<html>
<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></title>
</head>
<body>
<div id="app">
    <h2>价格为:{{price | priceFilter}}</h2>
</div>
</body>
</html>
<script src="./vue.js"></script>
<script>
new Vue({
    el: "#app",
    data: {
        price: 25.3
    },
  	// 局部过滤器
    filters: {
        priceFilter(val){
            return "¥ "+val.toFixed(2)+" 元";
        }
    }
})
</script>
// 全局过滤器
Vue.filter("priceFilter", function(val){
    return "¥ "+val.toFixed(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>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <style>
    table {
      border: 1px solid #e9e9e9;
      border-collapse: collapse;
      border-spacing: 0;
    }

    td,
    th {
      padding: 8px 16px;
      border: 1px solid #e9e9e9;
      text-align: left;
    }
    th {
      background-color: #f7f7f7;
    }
  </style>
</head>

<body>
  <div id="app">
    <table>
      <thead>
        <tr>
          <th v-for="(title,index) in titles" :key="index" v-text="title"></th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item,index) in books" :key="item.id">
          <td v-text="index"></td>
          <td v-text="book.name"></td>
          <td v-text="book.date"></td>
          <td>{{book.price | priceRule}}</td>
          <td>
            <button @click="sub(index)">-</button>
            <span>{{book.num}}</span>
            <button @click="add(index)">+</button>
          </td>
          <td>
            <button @click="remove(index)">移除</button>
          </td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="6">总价格:{{totalPrice | priceRule}}</td>
        </tr>
      </tfoot>
    </table>
  </div>
</body>
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      titles: ['编号', '书籍名称', '出版日期', '价格', '购买数量', '操作'],
      books: [
        {
          id: 1,
          name: '算法导论',
          date: '2006-9',
          price: 85,
          num: 1
        },
        {
          id: 2,
          name: 'UNIX编程艺术',
          date: '2006-2',
          price: 59,
          num: 1
        },
        {
          id: 3,
          name: 'Vue程序设计',
          date: '2008-10',
          price: 35,
          num: 1
        },
        {
          id: 4,
          name: '颈椎康复',
          date: '2006-3',
          price: 129,
          num: 1
        }
      ]
    },
    filters: {
      priceRule(value) {
        return '¥' + value.toFixed(2)
      }
    },
    computed: {
      totalPrice() {
        return this.books.reduce((prev, current)=> {
          prev +=current.num * current.price
          return prev
        }, 0)
      }
    },
    methods: {
      add(idx){
        this.books[idx].num++
      },
      sub(idx){
        this.books[idx].num--
        if (this.books[idx].num == 0) {
          this.books.splice(idx, 1)
        }
      },
      remove(idx){
        this.books.splice(idx, 1)
      }
    }
  })
</script>

</html>

八、本地存储(掌握)

localStorage永久存储

// 添加数据;setItem的value值是字符串类型的数据
localStorage.setItem('name','张三');
// 获取数据
localStorage.getItem('name'); // 张三
// 清空
localStorage.clear();

注意事项:

  1. 除非是主动删除,不然是不会自动删除的

  2. 一般浏览器存储的大小是5M

5M = 1024 * 5kb

sessionStorage临时会话存储

// 添加数据;setItem的value值是字符串类型的数据
sessionStorage.setItem('name','张三');
// 获取数据
sessionStorage.getItem('name'); // 张三
// 清空
sessionStorage.clear();

注意事项:

  1. 关闭浏览器会自动清空数据

  2. 一般浏览器存储的大小是5M

  1. cookie:

网站中,http请求时无状态的。也就是第一次登陆成功(发送请求),第二次请求服务器依然不知道是哪一个用户。这时候的cookie就是解决这个问题的,第一次登陆后服务器返回数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求,浏览器自动会把上次请求存储的cookie数据自动带上给服务器,服务器根据客户端的cookie来判断当前是哪一个用户。cookie存储有大小限制,不同浏览器不一样,一般是4kb,所以cookie只能存储小量数据。

4kb = 4 * 1024 byte (字节) = 4 * 1024 * 8 bit(位)

服务器会把第一次登陆后服务器返回的cookie存储到浏览器中

​ 发一个请求给后端(自动带上第一次登陆后的cookie),拿回我自己购物车的列表

服务端接收到这个请求后,根据浏览器带上的cookie做出判断,判断当前是哪一个用户

  1. session:

session和cookie的作用有点类似,也是存储用户相关信息。不同的是cookie存储在浏览器,而session存储在服务器。

九、作业

独自完成图书馆购物车案例。

最后更新于