Day02 ES6语法基础和Vue指令(中)

Day02 ES6语法基础和Vue指令(中)

一、let/const

let用来定义变量, const用来定义常量。

let

var的缺陷:没有块级作用域, 可以在任意地方使用定义的var变量。

ES6之前if和for没有块级作用域,变量可以任意使用。举个例子,实现点击按钮时弹出是第几个按钮时会产生一些问题, 现象是不管点击哪个按钮都会提示点击了最后一个按钮,点击效果如下:

代码

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
  //ES5
  var btns = document.getElementsByTagName('button');
  for (var i = 0; i < btns.length; i++) {
    btns[i].addEventListener('click', function () {
      alert('点击了' + i + '个按钮');
    })
  }
</script>

因为var变量在for中没有块级作用域,所以函数调用i变量时会调用外层定义的i,而i最终循环完毕的值是3,所以发生错误。

解决办法

  • 使用函数闭包解决

ES5中函数是有作用的,可以借助函数闭包解决这个问题。因为使用的是函数自己定义的变量,所以不会发生数据共享问题

var btns = document.getElementsByTagName('button');

//ES5闭包
for (var i = 0; i < btns.length; i++) {
    // 将i传进去
    (function (i) {
      btns[i].addEventListener('click', function () {
        alert('点击了' + i + '个按钮');
      })
    })(i)
}
  • 使用let定义变量

let定义的变量在for和if中有块级作用域

for (let i = 0; i < btns.length; i++) {
    btns[i].addEventListener('click', function () {
      alert('点击了' + i + '个按钮');
    })
}

效果

const

将标识符修饰为常量,其值不允许改变。

建议首选const,只有需要改变时使用let,这样符合代码的规范性。

注意:const定义的标识符必须被初始化;const定义的对象不能修改,但是对象的属性可以改变;

对象字面量增强写法

字面量:定义的对象使用的{}。

一般写法

// const obj = new Object();
cosnt obj = {
    name: 'admin',
    age: 23,
    eat: function() {
        ...
    },
    run: function() {
        ...
    }
};

增强写法

const name = 'admin';
const age = 23;
cosnt obj = {
    name,
    age,
    eat () {
        ...
    },
    run () {
        ...
    }
};

二、v-on事件监听

因为前端经常会和用户进行交互,所以会监听点击、拖拽、键盘等事件。vue中使用v-on实现事件的监听。

基本用法

前面计数器案例已经演示过了,可以使用更加简洁的写法,代码如下:

<div id="app">
  <h2>{{counter}}</h2>
  <!--<button v-on:click="add()">+</button>
  <button v-on:click="sub()">-</button>-->
  <button @click="add()">+</button>
  <button @click="sub()">-</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      counter: 0
    },
    methods: {
      add() {
        this.counter++;
      },
      sub() {
        this.counter--;
      }
    }
  })
</script>

当没有参数是括号可以省略。

v-on参数传递

  • 当没有参数时,有括号和没括号打印结果相同
<div id="app">
  <!--<button @click="printStr()">按钮1</button>-->
  <button @click="printStr">按钮1</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: 'Hello, Vue!'
    },
    methods: {
      printStr() {
        console.log(this.message);
      }
    }
  })
</script>

两个按钮点击后都会打印"Hello, Vue!"。

  • 当只有一个参数时,去掉括号会打印event对象(事件对象,可以获得鼠标、键盘等事件的状态)
<div id="app">
  <button @click="printStr1()">按钮1</button>
  <button @click="printStr1(123)">按钮2</button>
  <button @click="printStr1">按钮3</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: 'Hello, Vue!'
    },
    methods: {
      printStr1(abc) {
        console.log(abc);
      }
    }
  })
</script>

结果如下图所示

当不传参数时,abc为默认值undefined;

当传递存在的参数时,会打印参数结果;

当省略括号时,会默认传递event对象。

  • 当传递多个参数时,去掉括号传递会将第一个参数作为event对象;传递event对象需要使用$event
<div id="app">
  <button @click="printStr2(123, event)">按钮1</button>
  <button @click="printStr2">按钮2</button>
  <button @click="printStr2(123, $event)">按钮3</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: 'Hello, Vue!'
    },
    methods: {
      printStr2(abc, event) {
        console.log("多个参数传递:", abc, event)
      }
    }
  })
</script>

结果如下

  1. 当传递event时,会当做普通变量,由于普通变量未定义所以报错;
  2. 当省略括号时,会将第一个变量当做event对象打印,第二个打印默认值undefined;
  3. 当传递正确的参数和$event时会打印正确结果

v-on修饰符

stop修饰符

用于禁止冒泡事件发生(当div存在监听事件时,在div里面button的监听事件触发时div的事件也会出发)。

prevent修饰符

阻止默认事件提交,比如在表单中,需要使submit按钮的点击事件生效,就需要禁用submit按钮的默认提交事件。

enter修饰符

用在监听键盘按下(keyDown)或抬起事件(keyUp)中,只监听回车事件发生。也可以只用键盘代号表示键盘上的任意键。

once修饰符

事件只会触发一次。

这四个修饰符的代码示例如下:

<div id="app">
  <!-- 阻止事件冒泡 -->
  <div @click="divClick">
    aaaaaaa
    <!-- <button @click="btnClick">按钮</button> -->
    <button @click.stop="btnClick">按钮1</button>
  </div>
  <!-- 阻止默认事件提交 -->
  <form action="abc">
    <input type="submit" @click.prevent="btnClick" value="提交">
  </form>
  <br>
  <!-- 监听回车事件 -->
  <input type="text" @keyDown.enter="keyDo">
  <!-- button只会点击一次 -->
  <button @click.once="btnClick">按钮2</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "Hello, Vue!"
    },
    methods: {
      divClick() {
        console.log("div被点击");
      },
      btnClick() {
        console.log("btn被点击");
      },
      keyDo() {
        console.log("键盘事件触发");
      }
    }
  })
</script>

其他修饰符需要自己了解。

三、条件判断指令

v-if/v-else指令

类似于Java中的if/else语句

<div id="app">
  <h2 v-if="isShow">
    v-if为true时显示
  </h2>
  <h2 v-else>
    v-if为false时显示
  </h2>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: 'Hello, Vue!',
      isShow: true
    }
  })
</script>

当isShow为true时显示"v-if为true时显示",当isShow为false时显示"v-if为false时显示"。

v-if-else指令

类似Java中的if-else语句,在多个条件中,当其中一个条件满足时不会执行其他判断语句

打印成绩等级案例

<div id="app">
  <h2 v-if="scorce>=90">优秀</h2>
  <h2 v-else-if="scorce>=70">良好</h2>
  <h2 v-else-if="scorce>=60">及格</h2>
  <h2 v-else>不及格</h2>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      scorce: 85
    }
  })
</script>

打印结果为良好。

切换登录方式案例

目前有用户登录和邮箱登录,当点击按钮后切换邮箱登录方式。

代码

<div id="app">
  <span v-if="!isAlter">
    <label for="username">用户名</label>
    <!-- 存在标签复用问题 -->
<!--    <input id="username" type="text" placeholder="用户名">-->
    <input id="username" type="text" placeholder="用户名" key="username">
  </span>
  <span v-else>
    <label for="email">邮箱</label>
    <input id="email" type="text" placeholder="邮箱" key="password">
  </span>
  <button @click="isAlter=!isAlter">切换登录方式</button>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      isAlter: false
    }
  })
</script>

问题

存在标签复用问题,当点击切换按钮式后,用户输入框的数据会带到邮箱输入框。

因为vue底层通过虚拟DOM(Virtual DOM)渲染浏览器。当渲染邮箱输入框时,只会从Virtual DOM中获取不同的数据进行渲染。因为value值没有改变,所以会在邮箱输入框里显示。

解决方法

使用key关键字用于区分不同输入框。

<input id="username" type="text" placeholder="用户名" key="username">

v-if和v-show的区别

v-if生效时不会在DOM中显示标签,而v-show生效时会在DOM中显示标签并增加一个行内样式display:none。当需要频繁切换时,使用v-show,性能更高;当只进行一次切换时使用v-show。

四、v-for指令

遍历数组

遍历普通数组

arr: ['marry','tom','joey','Jerry']

代码

<ul>
    <li v-for="item in arr">{{item}}</li>
</ul>
<!--index是索引-->
<ul>
    <li v-for="(item,index) in arr">{{index}}.{{item}}</li>
</ul>

遍历对象数组

objArr: [  {name:"張三", age:10},  {name:"張三三", age:20},  {name:"李四", age:30}]

代码

<ul>
    <li v-for="item in objArr">{{item.name}}</li>
</ul>

遍历对象元素

对象数据如下

info:{  name: 'Marry',  age: 35,  email: '2294678909@qq.com',  gender: 'female'}

获取值

<ul><li v-for="item in info">{{item}}</li></ul>

获取键和值

<ul><li v-for="(value,key) in info">{{key}}-{{value}}</li></ul>

获取索引(很少用)

<ul><li v-for="(value,key,index) in info">{{index}}{{key}}-{{value}}</li></ul>

v-for绑定key作用

场景描述

当遍历数组时需要在数组中添加元素,怎么做是最高效的方式来渲染数组列表。

代码实现

<div id="app">
  <ul>
<!--    <li v-for="item in arr">{{item}}</li>-->

    <li v-for="item in arr" :key="item">{{item}}</li>
  </ul>
</div>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      arr: [
          'a',
          'b',
          'c',
          'd'
      ]
    }
  })
</script>

原理解析

virtual DOM是将真实的 DOM 的数据抽取出来,以对象的形式模拟树形结构,diff算法比较的也是virtual DOM

现在要在a和b之间插入f。没有绑定key时, Virtual DOM先把b改为f,c改为b,以此类推,最后在末尾添加一个d元素,效率十分低下。

当绑定了**:key=“唯一标识后”**, 可以正确的识别此节点,找到正确的位置区插入新的节点, 提高了效率。

注意index不能作为唯一标识,因为当插入f时此时对应的index为1,与b的index重复,使得key无效。

五、响应式数组方法

响应式数组函数

  • pop():在末尾删除一个元素。
  • shift():在首部删除一个元素。
  • unshif(…items: T[]):在首部添加一个或多个元素。
  • push(…items: T[]):在末尾添加一个或多个元素。
  • splice():替换/删除/插入元素(主要取决于第二个参数)。
const app = new Vue({
      el: "#app",
      data: {
        words: [
            'A',
            'B',
            'C',
            'D'
        ]
      },
      methods: {
        insert() { // A B F T C D
          // 在第三个位置插入F
          this.words.splice(2,0,'F','T');
        },

        remove() { // A B
          // 删除元素 
          this.words.splice(2, 3)
        },

        replace() { //A B F T D
          // 替换元素
          this.words.splice(2,1,'F','T');
        }
      }
})

第一个参数:开始操作的索引。

第二个参数:等于0时,为插入操作;大于0时,为删除或替换操作。

其他参数:要插入或替换的元素。

关于替换的理解:先删除,后插入。

  • sort():排序,参数可以为函数,也可以不进行传参

对象的属性排序:按person对象的年龄进行操作

const app = new Vue({
    el: "#app",
    data: {
      persons: [
        {name: 'admin', age: 24},
        {name: 'fyee', age: 34},
        {name: 'tomcat', age: 14},
        {name: 'tt', age: 43},
      ]
    },
    methods: {
      sortByAge() { //传入的是两个person对象
        this.persons.sort((a, b) => {
          //升序排序
          return a.age - b.age;
        })
      }
    }
  })
  • reverse():反转数组。

赋值语句问题

赋值语句无法响应式的改变基本类型的页面数据,但可以改变对象的属性

const app = new Vue({
    el: "#app",
    data: {
      books: [
        'A',
        'B',
        'C',
        3
      ]
    },
    methods: {
      modifyA() { //页面数据不会改变
        this.books[0] = 'AAA';
        console.log(this.books)
      },

      modifyAA() { //页面数据改变
        this.books.splice(0, 1, 'AAA')
        console.log(this.books)
      },

      modifyB() { //对象属性改变
        this.persons[0].name = 'cetc27';
        this.persons[0].age = 88;
      },

      modifyBB() { //对象改变

        const person = {name: 'cetc27', age: 88}
        this.persons.splice(0, 1, person)
      },
    }
  })

当通过赋值语句改变基本类型数组时,页面数据不会改变,但是数组元素已经发生变化。

当通过赋值语句改变对象数组时,页面数据会发生改变,本质上对象没有发生改变,改变的是对象的属性。

六、综合案例:购物车

需求说明

  1. 遍历数组中元素,显示在页面上
  2. 当购物车没有数据时显示当前购物车为空
  3. 当购买数量为1时禁用减少按钮
  4. 实现移除按钮,移除数组中一项
  5. 打印总价

步骤

1. v-for遍历数组,显示在页面上

<table>
      <thead>
      <tr>
        <th></th>
        <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>
        <td>{{item.date}}</td>
        <td>{{item.price | priceFilter}}</td>
        <td>
            <button @click="sub(index)" :disabled="item.count<=1">-</button>						{{item.count}}
            <button @click="add(index)">+</button>
        </td>
        <td><button @click="remove(index)">移除</button></td>
      </tr>
      </tbody>
</table>

2. 需要添加过滤器,保留小数点后两位数据

const app = new Vue({
  ...
  filters: {
    priceFilter(price) {
      return '¥' + price.toFixed(2)
    }
  }
  ...
})

3. 添加点击事件, 实现数量增减和移除数组元素功能

const app = new Vue({
	...
    methods: {
    add(index) {
      this.books[index].count++;
    },

    sub(index) {
      this.books[index].count--;
    },

    remove(index) {
      this.books.splice(index, 1);
    }
  }
  ...
})

4. 通过计算属性显示总价

const app = new Vue({
	...
    computed: {
        totalPrice() {
          let result = 0;
          for (const book of this.books) {
            result += book.price * book.count;
          }

          return result;
        }

        /*totalPrice: function () {
          let result = 0;
          for (const book of this.books) {
            result += book.price * book.count;
          }

          return result;
        }*/
	}
  ...
})
<h2>总价格:{{totalPrice | priceFilter}}</h2>

5. 通过v-if控制购物车是否显示

<div v-if="books.length>0">
    ...
</div>
<div v-else>
	<h2>购物车中没有商品</h2>
</div>

效果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值