02-Vue的事件的绑定与渲染指令

02-Vue的事件的绑定与渲染指令

主要内容

  • Vue实例配置methods选项
    • methods实例配置选项
    • Vue事件绑定函数
  • 修饰符
    • 事件修饰符
    • 按键修饰符
  • 条件渲染
    • 指令 v-if
    • 指令 v-show
  • 列表渲染
    • 指令 v-for
  • 更新检测
    • 数组的更新
    • 对象的更新

介绍

上一章我们已经学习了如何通过v-on指令对Vue中的DOM节点进行事件绑定。

本章我们继续学习Vue的事件处理,并学习如何向Vue的事件绑定指令中添加逻辑处理函数实现复杂的事件绑定逻辑

Vue实例配置methods选项

在学习Vue事件绑定函数之前,我们需要学习如何在Vue实例中创建实例对象自身的方法函数。创建Vue实例对象的方法同样需要通过Vue实例配置选项来创建。

methods实例配置选项

语法{ [key: string]: Function }

介绍:methods配置对象将被混入到 Vue 实例中作为当前实例的方法。 VM 实例可以直接访问该对象内的方法,或者在指令表达式中使用他们。methods对象中的方法的 this 会自动绑定为 Vue 实例。

<!-- 在指令表达式中使用-->
<div id='app'>{{reverseStr()}}</div>

<script>
var vm = new Vue({
  el: '#app',  
  data: {
           a: 1 ,
           str: 'hello world'
        },
  methods: {
    addA: function () {
      this.a++
    },
    reverseStr() { // ES6写法
       return this.str.split('').reverse().join('')
    }
  }
})
vm.addA() // 通过Vue实例对象直接访问methods内部的方法
vm.a // 2
</script>
Vue事件绑定函数

介绍: 在Vue的v-on事件绑定语法,支持将函数作为js表达式绑定到监听事件中。当目标元素的事件被触发时绑定的函数将会被执行。

注意:

  1. v-on事件绑定中js表达式传入函数,函数名后不显式添加()会被vue隐式默认添加(),并且会默认的将event原生事件对象作为参数传入到函数中
<div id="app">
<!--     被点击会打印undefined,因为函数显示被调用并没有向函数内部传递任何参数-->
    <button @click="clickHandel()">click me</button>
<!--     被点击会打印事件对象event,vue会隐式调用该函数并传递event作为当前函数的参数-->
    <button @click="clickHandel">click me</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
        new Vue({
            el: '#app',
            methods: {
                clickHandel(event) {
                    console.log(event)
                }
            }
        })
</script>
  1. 如果需要在事件绑定函数中不但手动传参还要传递event事件对象,需要使用vue实例对象提供的特殊变量 $event ,将事件对象手动传递给函数内部
<div id="app">
     // 向函数手动传递参数 $event是vue所提供的当前原生事件对象特殊变量
      <button @click="clickHandel($event,12)">click me</button> 
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
        new Vue({
            el: '#app',
            methods: {
                clickHandel(event,num) {
                    console.log(event,num)
                }
            }
        })
</script>

修饰符

概念: 在事件处理程序中用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。简化上面这种DOM事件细节需求

语法: v-on:事件名.修饰符1.修饰符2...

事件修饰符

.stop 阻止事件冒泡

<div id="app">
    <div :style="{width: '200px',height: '200px',backgroundColor: 'red'}" @click="clickHandle($event,'div')">
        <p :style="{width: '120px',height: '120px',backgroundColor: 'green'}"
           @click.stop="clickHandle($event,'p')">
            <a @click.stop="clickHandle($event,'a')">我是A标签</a>
        </p>
    </div>
</div>

    <script>
        new Vue({
            el: '#app',
            methods: {
                clickHandle(event, detail) {
                    console.log(detail + '被点击了', event.target)
                }
            }
        })
    </script>

.prevent 阻止事件浏览器默认行为

<form>
    <input @click.prevent="clickHandle($event,'submit')" type="submit">
</form>

.capture 事件使用捕获

<div :style="{width: '200px',height: '200px',backgroundColor: 'red'}" 
     @click.capture="clickHandle($event,'div')">
    <p :style="{width: '120px',height: '120px',backgroundColor: 'green'}"
       @click.capture="clickHandle($event,'p')">
         <a @click="clickHandle($event,'a')">我是A标签</a>
    </p>
</div>

.self event.target必须是绑定事件的元素自身才能触发

<div :style="{width: '200px',height: '200px',backgroundColor: 'red'}" 
     @click="clickHandle($event,'div')">
    <p :style="{width: '120px',height: '120px',backgroundColor: 'green'}"
       @click.self="clickHandle($event,'p')">
        <a @click="clickHandle($event,'a')">我是A标签</a>
    </p>
</div>

.once 事件只触发一次

 <div :style="{width: '200px',height: '200px',backgroundColor: 'red'}" 
      @click="clickHandle($event,'div')">
    <p :style="{width: '120px',height: '120px',backgroundColor: 'green'}"
       @click.self.stop.once="clickHandle($event,'p')">
        <a @click="clickHandle($event,'a')">我是A标签</a>
    </p>
 </div>

.passive 提高移动端scroll事件滑动性能的修饰符,该修饰符不能与 .prevent 一起使用

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
按键修饰符

概念: 在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符

修饰符种类:

  • KeyboardEvent.key修饰符

介绍: Vue支持 键盘事件中每个键的key按键名转换为 kebab-case 来作为修饰符。

语法v: -on:事件名.[event.key]

// 按键盘page down键触发
<textarea @keyup.page-down="keyUpHandle"></textarea>
// 按键盘a触发
<textarea @keyup.a="keyUpHandle"></textarea>
// 按键盘a或者s触发
<textarea @keyup.a.s="keyUpHandle"></textarea>

注意: 为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名

修饰符描述
.enter回车键
.tabTab键
.delete捕获“删除”和“退格”键
.escESC键
.space空格键
.up方向键上
.down方向键下
.left方向键左
.right方向键右
  • 系统修饰键

介绍: 系统修饰键可以配合其他按键一起按下相应按键时才触发鼠标或键盘事件的监听器。

语法: v-on:事件名.系统修饰键.[event.key]

修饰符描述
.ctrlctrl键
.altalt键
.shiftshift键
.meta在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。
// 在按下shift键后再按其他键才会触发
<textarea @keyup.shift="keyUpHandle"></textarea>
// 在按下shift键后按a键才会触发
<textarea @keyup.shift.a="keyUpHandle"></textarea>
// 在按下shift键ctrl键后再按a键才会触发
<textarea @keyup.shift.ctrl.a="keyUpHandle"></textarea>

注意: vue在2.5.0 新增 .exact

介绍: 修饰符(严格修饰符),该修饰符的功能是,严格控制系统修饰键按压

// 非严格模式下在按下shift键ctrl键后再按a键也会触发
<textarea @keyup.shift.a="keyUpHandle"></textarea>
// 严格模式下在按下shift键ctrl键后再按a键不会触发
// 只有仅按shift键没有按下其他系统修饰键的情况下按a才会触发
<textarea @keyup.shift.a.exact="keyUpHandle"></textarea>
  • 鼠标按钮修饰符

概念: 鼠标修饰符会限制处理函数仅响应特定的鼠标按钮。

修饰符描述
.left鼠标左键
.right鼠标右键
.middle鼠标中间滚轮键

条件渲染

指令 v-if

概念: 允许使用 v-if / v-else / v-else-if 控制元素的渲染
语法: <元素 v-if="判别式" />

<div id="app">
        <div 
            :style="{width: '100px',height: '100px', backgroundColor: 'red'}"
            v-if="show"
        ></div>
        <button @click="show = !show">show/hidden</button>
</div>

<script>
        new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
</script>

语法: <元素1 v-if="判别式" /> <元素2 v-else />

 <div id="app">
        <div 
            :style="{width: '100px',height: '100px', backgroundColor: 'red'}"
            v-if="show">
            白天
        </div>
        <!--v-if元素 与 v-else元素之间除了空行和注释以外不能有其他元素否则会报错-->
        <div :style="{width: '100px',height: '100px', backgroundColor: '#ccc'}" v-else>
            晚上
        </div>
        <button @click="show = !show">show/hidden</button>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
    </script>

语法: <元素1 v-if="判别式" /> <元素2 v-else-if="判别式" /> ... <元素n v-else />

<div id="app">
    <!--注意v-if v-else-if v-else元素之间除了空行和注释以外不能有其他任何节点-->
  <div v-if="score > 90">
    优秀
  </div>
  <div v-else-if="score >= 85">
    良好
  </div>
  <div v-else-if="score >= 60">
     及格
  </div>
  <div v-else>
    不及格
  </div>
</div>

<script>
let vm = new Vue({
            el: '#app',
            data: {
                score: 50
            }
        })
</script>
指令 v-show

概念: 允许使用 v-show 控制元素的显示隐藏

语法: v-show="判别式"

<div id="app">
    <div v-show="show" style="width: 100px;height: 100px;background-color: red;">show</div>
    <button @click="show = !show">show/hidden</button>
</div>

<script>
let vm = new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
</script>

注意:

  • v-if指令实现元素的隐藏是直接将该元素从DOM节点中删除,而v-show隐藏元素只是设置了元素的display: none属性并没有把元素从DOM节点中移除。因为上面的特性在开发中需要频繁显示隐藏的元素请使用v-show,而只需显示一次的元素请使用v-if
  • Vue 会尽可能高效地渲染元素,通常在使用v-if切换元素时, 会复用已有元素而不是从头开始渲染,下面的例子中元素切换并没有真的卸载掉上一个表单元素重新安装,而是复用了该元素只是修改其placeholder的属性值,在下面的的代码中切换 show 将不会清除用户已经输入到表单的内容
<div id="app">
    <!--请在表单元素中输入内容后切换元素查看效果-->
    <input v-if="show" placeholder="请输入密码">
    <input v-else placeholder="请输入验证码"> 
    <button @click="show = !show">show/hidden</button>

</div>

<script>
let vm = new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
</script>
  • Vue提供了一个key属性来表示元素的独立性,简单来说key属性的值是一个字符串。只有在兄弟元素(同一个if语句,同一个循环的同级元素)中key属性相同的元素才可以互相复用。下面的代码中 两个兄弟表单元素因为key属性不同不能互相复用。所以在元素切换时上一个表单元素会被卸载,重新渲染新的表单元素
<div id="app">
     <!--请在表单元素中输入内容后切换元素查看效果-->
     <input key="1" v-if="show" placeholder="请输入密码">
     <input key="2" v-else placeholder="请输入验证码"> 
     <button @click="show = !show">show/hidden</button>
</div>

<script>
let vm = new Vue({
            el: '#app',
            data: {
                show: true
            }
        })
</script>

列表渲染

指令 v-for

概念: Vue可以使用户v-for遍历数组或者对象循环渲染多个相同DOM节点

语法: v-for="item in <Array>" item为数组每一项的值

 <div id="app">
     <ul>
    <li v-for="item in arr" :key="item" :class="'item-'+item">{{item}}</li>
    </ul>
 </div>

 <script>
   new Vue({
        el: '#app',
        data: {
            arr: ['a', 'b', 'c', 'd']
        }
  })
</script>

语法: v-for="(item, index) in <Array>" item为数组每一项的值,index为对应项的下标

<div id="app">
        <ul>
            <li v-for="(item,index) in arr" :key="index" :class="'item-'+index">{{item}}</li>
        </ul>
    </div>

<script>
        new Vue({
            el: '#app',
            data: {
                arr: ['a', 'b', 'c', 'd']
            }
        })
</script>

语法: v-for="value in <Object>" value为数组每一项键值对的value值

<div id="app">
        <ul>
           <li v-for="val in obj" :key="val">{{val}}</li>
        </ul>
</div>

<script>
        new Vue({
            el: '#app',
            data: {
               obj: {
                   name: '小明',
                   age: 19,
                   address: '深圳'
               }
            }
        })
</script>

语法: v-for="(value,key) in <Object>" value为数组每一项键值对的value值,key为对应键值对的键名

<div id="app">
    <ul>
        <li v-for="(val,key) in obj" :key="key">{{key}}:{{val}}</li>
    </ul>
</div>

<script>
        new Vue({
            el: '#app',
            data: {
               obj: {
                   name: '小明',
                   age: 19,
                   address: '深圳'
               }
            }
        })
</script>

语法: v-for="(value, name, index) in <Object>" value为数组每一项键值对的value值,key为对应键值对的键名,index为对应键值对的下标

  <div id="app">
        <ul>
           <li v-for="(val,key,index) in obj" :key="index" :class="'item-'+index">{{key}}:{{val}}</li>
        </ul>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
               obj: {
                   name: '小明',
                   age: 19,
                   address: '深圳'
               }
            }
        })
    </script>

注意: 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态(当前列表不会增加,删除,更新顺序)。解决方法,为每一个使用v-for遍历出来的DOM节点添加一个唯一key属性,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。key属性不需要做到全局唯一,只需要同一个循环遍历的兄弟元素之间不同就好了

注意: 数组排列或者删除的操作请谨慎使用index作为key,index无论怎么删除下标永远都是从0 到 n,导致会删除掉错误dom节点

更新检测

概念: Vue数据双向绑定的原理是在vue实例初始化时递归的给所有的对象属性绑定getter/setter方法,这样导致了两个问题:

1. 数组的更新,

介绍: 数组的每一项不会被vue递归的绑定get/set,所以在vue中数组通过下标添加或者修改值的时候不会引起页面更新。

注意: Vue 的数组的 push() pop() shift() unshift() splice() sort() reverse()方法会触发视图更新

<div id="app">
    <p v-for="(item,index) in arr" :key="index">{{item}}</p>
</div>

let vm = new Vue({
            el: '#app',
            data: {
                arr: ['a','b','c','d']
            }
})

vm.arr[1] = 'AAA'  // 页面不会更新
vm.arr[4] = 'e' // 页面不会更新

可以引起数组更新视图的方法有三种:

  • 方法一: 调用上面说的数组中的方法
  • 方法二: 使用新数组替换旧数组
  • 方法三: 使用vm.$set 或者Vue.set方法修改数组指定下标的值

语法: vm.$set(数组,index,val) 或者 Vue.set(数组,index,value)

let vm = new Vue({
            el: '#app',
            data: {
                arr: ['a', 'b', 'c', 'd']
            }
        })
/*
vm.arr[1] = 'AAA' // 页面不会更新
vm.arr[4] = 'e' // 页面不会更新
*/
Vue.set(vm.arr, 1, 'CCCC') // 页面会更新
vm.$set(vm.arr, 4,'eee')// 页面会更新
2. 对象的更新

介绍: 因为在Vue初始化时对象中的所有属性都被添加了get/set,所以对象可以直接通过属性名修改就会引起页面的更新,但是如果在Vue实例化之后给某个对象添加新的属性,这个属性将不包含get/set方法。增加新属性或修改这个新属性就不会引起页面更新。

给对象添加新属性并引起页面更新的方法有两种:

  • 方法一: 新对象替换旧对象
  • 方法二: vm.$set / Vue.set 添加新属性,自动给新属性绑定get set方法

语法: Vue.set(对象,'键名',属性值) 或者 vm.$set(对象,'键名',属性值)

<div id="app">
    <p v-for="(val,key) in obj" :key="key">{{val}}</p>
</div>
<script>
let vm = new Vue({
            el: '#app',
            data: {
                obj: {
                    name: '老李',
                    age: 18
                }
            }
        })

vm.$set(vm.obj, 'address', '深圳')  // 页面会更新
        
vm.$set(vm.obj, 'address', '广州')  // 页面会更新
     
vm.obj.address = '佛山' //address 自动添加get set 页面会更新
     
Vue.set(vm.obj, 'hobby', '吃肉') // 页面会更新
</script>

注意Vue.set / vm.$set只可以给data中的Object对象属性添加新属性,不可以给vm.$data对象自身添加新属性,但可以修改vm.$data已声明属性。

var vm = new Vue({
    el: '#app',
    data: {
        a: 1 ,
        str: 'hello world'
    }
})

vm.$set(vm.$data,'a', 2) // 正确, 可以使用set方法修改data对象已有属性
vm.$set(vm.$data, 'test', 10086) // 错误, 不可以使用set方法向data对象添加新属性

错误信息: Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.

避免在运行时向Vue实例或其根$data添加新性属性,请在data选项中预先声明。即请将data中可能用到的属性在初始化时预先声明。data对象不支持实例化后添加新属性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李鑫海。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值