基于全网最棒的Vue教学视频(尚硅谷张天禹老师)整理出的最详细的Vue指令笔记

本文详细介绍了Vue中的单向绑定(v-bind)与双向绑定(v-model)指令,以及条件渲染(v-show, v-if)的使用技巧,涵盖了列表渲染(v-for)和状态管理,同时探讨了关键的自定义指令和安全性措施。
摘要由CSDN通过智能技术生成

重要原则

  • 原理:普通函数内出现的this指向的是它的调用者,箭头函数中出现的this指向的是外部作用域的this指向
  • Vue管理的函数由Vue调用
  1. 所有被Vue管理的函数(不考虑嵌套),最好写出普通函数,这样this执行Vue实例

  2. 所有不被Vue管理的函数(不考虑嵌套),最好写出箭头函数,这样this才指向Vue实例

定时器的回调函数,ajax的回调函数

1. 插值语法

  • 语法:((xxx})
  • 作用:让Vue先计算出xxx的值,再用这个值替换((xxx})
  • xxx是js表达式,这个表达式中出现的属性或方法必须是JS原生的或者Vue实例身上的
  • 一个完整实例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="root">
        <h3>{{url}}</h3>
        <span>{{person.name}}</span>
        <!--hint:
           只能直接使用data对象的下一级属性,
           就是你可以直接写person,但是不能直接写name,
           只能借助person来访问name
        -->
    </div>
</body>

<script>
   new Vue({
      el: '#app',
      data: {
           url:"http://www.atguigu.com",
           person:{
              name:"liu"
           }
      }
   })    
</script>
</html>

1. 单向绑定:v-bind指令

  • 语法:v-bind:attribute=“xxx” ,简写为 :attribute=“xxx”(attribute必须是标签的属性)

  • 作用:让Vue先计算出xxx的值,再把这个值赋给attribute

  • 单向绑定:即不能通过在页面修改attribute的值来反向修改value的值,但反之可以

  • xxx是js表达式,这个表达式中出现的属性或方法必须是JS原生的或者Vue实例身上的

  • 完整的案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
    
<body>
<div id="app">
     <a v-bind:href="url">点我去尚硅谷</a>
</div>
</body>

<script>
const vm =  new Vue({
            el: '#app',
            data: {
               url:"http://www.atguigu.com",
            }
})
</script>
</html>
样式绑定
  • 样式与Vue实例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
    
<style>
    .one{
        width:100px
    }
     .two{
        width:100px
    }  
     .three{
        width:100px
    }  
</style> 

<script>
const vm =  new Vue({
            el: '#app',
            data: {
               styleOne:"one"
               styleArr:['one','two','three'],
               classStyle:{
                    one:false,
                    //不应用样式one
                    two:true
                    //应用样式two
               }
               styleObj:{
                   width:40px;
                   height:40px;
                   fontSize:16px 
                   //如果属性是css原生的(用的是短横线命名法),必须改成大驼峰命名 
                   //如:font-size 改成fontSize
               } 
            }
})
</script>
</html>
  • class样式的三种写法

    • 字符串式写法:适用样式的类名不确定
    <span :class="styleOne">1</span>
    
    • 数组式写法:适用样式的类名和个数不确定

    class=“one two three”,即span标签使用这三个样式

    <span :class="styleArr">2</span>
    
    • 对象式写法:适用样式的类名和个数确定,但是要动态决定用哪些
     <span :class="classStyle">3</span>
    
  • 内联样式的写法

style=“ width:40px;height:40px;font-size=16px”

<span :sytle="styleObj"></span>

2. 双向绑定:v-model指令

  • 语法:v-model:value =“xxx”,可以简写为v-model`=“xxx”,因为v-model默认绑定到value属性上
  • 作用:让Vue先计算出xxx的值,再把这个值赋给value
  • 双向绑定:能通过在页面修改value的值来反向修改value的值
  • note:该指令只能用于表单元素
  • xxx是js表达式,这个表达式中出现的属性必须是data对象中的,出现的方法必须是JS内置的方法或者Vue实例身上的
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
     <input type="text " v-model="input"> 
  
</div>
</body>

<script>
const vm =  new Vue({
            el: '#app',
            data: {
               input:"",
               person:{
                  name:"shen",
                  age:20
               }
            }    
})
</script>
</html>
收集表单数据

- <input type="text"/> : v-model收集的是value值,用户输入的就是value

<input type="text" v-model="sex"/> 
  • :v-model收集的是value值,但是要给标签配置value属性

value 属性对于 是必需的

<input type="radio" name="sex" v-model="sex" value="male"/>   
<input type="radio"  name="sex" v-model="sex" value="female"/>   
  • <input type="checkbox"/>

    • 没有给标签配置value属性,那么收集的就是checked(勾选or 未勾选,是布尔值)

    happy初始值为真值,对应的input标签默认被选中

    <input type="checkbox" v-model="happy"/>  
    <input type="checkbox" v-model="happy"/>  
    <input type="checkbox" v-model="happy"/> 
    
    <!--happy:"123"-->
    
    • 给标签配置了value属性:

      1. v-model的初始值是非数组,那么收集的就是checked(勾选 or未勾选,是布尔值

      happy初始值为真值,对应的input标签默认被选中

      <input type="checkbox" v-model="happy" value='study'/>  
      <input type="checkbox" v-model="happy" value='study'/>  
      <input type="checkbox" v-model="happy" value='study'/>  
      <!--happy:"123"-->
      
      1. v-model的初始值是数组,那么收集的的就是value组成的数组
      <input type="checkbox" v-model="happy" value='s'/>  
      <input type="checkbox" v-model="happy" value='t'/>  
      <input type="checkbox" v-model="happy" value='u'/>  
      <!--happy:[]-->
      
v-model修饰符
  • lazy:失去焦点再收集数据
  • number:输入字符串转为有效的数字
  • trim:输入首尾空格过滤
v-model.lazy= "sex"

3. 事件绑定:v-on指令

  • 语法:v-on:xxx="methodName",简写为@xxx="methodName"
  • 作用:当触发事件xxx时,执行methodName对应的方法
  • methodName:用参数event调用其对应的方法。event是触发的事件对象
  • methodName():不传参调用其对应的方法
  • methodName(num):用参数num调用对应的方法
  • methodName($event,num):用参数event,num调用对应的方法

无论用不用参数调用,对应的方法都可以不写参数

  • note:methods对象中的普通函数中出现的this是指向Vue实例,因为普通函数的this指向的是它的调用者,即Vue实例箭头函数中出现的this指向的是外部函数的this指向,即window对象

这里的结论不一定适应于嵌套方法

  • 完整案例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
  
    <button @click="printOne">1</button>
    <button @click="printTwo">2</button>
    <button @click="printThere">3</button>
    <button @click="printFour(1)">4</button>

</div>
</body>

<script>
    new Vue({
        el: '#app',
        methods: {
            
            printOne(event) {
                console.log(event.target.innerText)
                //拿到触发事件的标签的内容
            },

            printTwo() {
                console.log(this)
            },

            printThere: () => {
                console.log(this)
            },

            printFour(num) {
                console.log(num)
                console.log(num.target.innerText)
            }
        }
    })
    </script>
</html>
Vue中的事件修饰符
  1. prevent:阻止默认事件
    • a标签的默认事件是转跳
    • form标签的默认事件会重载页面
<!--假设调用printOne函数会弹窗-->

<a href="" @click="printOne">点我转跳</a>
<!--
当你点击时,会先弹窗,然后转跳
-->

<a href="" @click.prevent="printOne">点我转跳</a>
<!--
当你点击时,只会弹窗,弹窗之后不会转跳
-->
  1. stop:阻止事件冒泡
    • 事件冒泡:当一个元素接收到事件时,会把它接收到的事件逐级向上传播给它的祖先元素,一直传到顶层的 window 对象
<!--假设调用printOne函数会弹窗-->
<div @click="printOne">
    <button @click="printOne">1</button>
</div>
<!--
当你点击按钮时,先执行按钮身上的点击事件,然后事件会冒泡到div上,触发div身上的点击事件
-->

<div @click="printOne">
    <button @click.stop="printOne">1</button>
</div>
<!--
当你点击按钮时,先执行按钮身上的点击事件,但是Vue会阻止事件冒泡到div身上,因此不会在触发div身上的点击事件
-->
  1. once:事件只触发一次
  2. capture:使用事件捕获模式,(事件默认是冒泡的)
    • 事件捕获:就是最顶层的 window 对象最早接收事件,最低层的具体被操作的元素最后接收事件
<!--假设调用print函数会打印传入的参数-->
<div @click.capture="print(1)">
    <button @click="print(2)">1</button>
</div>
<!--结果:打印1-->
  1. self:只有event.target是当前的元素时才触发事件
<!--假设调用printOne函数会弹窗-->
<div @click.self="printOne">
    <button @click="printOne">1</button>
</div>
<!--
当你点击按钮时,先执行按钮身上的点击事件,然后事件会冒泡到div上,Vue会判断event.target是不是这个div,发现不是不触发div身上的点击事件
-->
  1. passive:事件的默认行为立即执行,无需等待事件回调执行完毕

移动端和平板端用的多

#####按键事件的修饰符

  1. 按键事件

    • keydown:按下键盘键触发事件

    • keyup:释放键盘键触发事件

    • keypress:按下并抬起同一个按键触发事件

  2. Vue提供的常用按键的别名

    • 回车键:enter
    • 删除键和退格键:delete
    • 退出键:esc
    • 空格键:space
    • 换行键:tab(必须搭配keydown事件去使用)

    因为tab可以把光标从当前元素身下切走,keyup.tab:当你按下tab键时就已经失去了对元素获取焦点,所有无法触发对应的函数

    • 上:up
    • 下:down
    • 左:left
    • 右:right
<input type="text" @keyup.enter="print">
<!--
  当释放按下的回车键时调用print函数
-->
<input type="text" @keyup.enter="print">
<!--
  当释放按下的回车键时调用print函数
-->
  1. Vue未提供别名的按键,可以使用按键原始的名字去绑定,但要注意转为短横线命令(单词首字母小写,单词之间用短横线连接)

JS按键名

按键对应的keyCode被web标准弃用了

<input type="text" @keyup.caps—lock="print">
<input type="text" @keyup.13="print">
  1. 自定义键名
    • 通过Vue.config.keyCodes.键名 = 键码来定义按键别名
<script>
    Vue.config.keyCodes.huiche = 13
    new Vue({
        el: '#app',
    })
    </script>
  1. 特殊的系统修饰键:ctrl,alt,shift,win

  2. 配合keyup键使用时:按下修饰键的同时,再按下其他键,随后释放其他键,事件才触发

  3. 配合keydown键使用时:正常触发

3.条件渲染

  • xxx:表示这是个JS表达式,这个表达式中出现的属性或方法必须是JS原生的或者Vue实例身上的
  • 作用:控制节点是否展示在页面
1. v-show指令
  • 语法:v-show=“xxx”,xxx为false即不展示该元素,反之展示
  • 用法:适用于切换频率较高的场景,v-if 有更高的切换开销
  • note:不管初始条件是什么,元素总是会被渲染
  • 该指令 不支持 <template> 元素
<span v-show="false">
2. v-if 指令
  • 语法:v-if = “xxx”, v-else-if = “xxx”,v-else = “xxx”
  • xxx === false:对应的DOM元素直接被移除,反之不移除
  • 用法:适用于切换频率较低的场景,v-show 有更高的初始渲染开销
  • note:v-if惰性的,它直到条件第一次变为真时,才会开始渲染条件块

最终的渲染结果将不包含 元素

<!--可以切换template标签下的所有标签-->

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

  • 搭配1
<div v-if="type === 'A'"> A</div>
<div v-else-if="type === 'B'"> B</div>
<div v-else="type === 'C'">  C</div>
  • 搭配2
<div v-if="type === 'A'"> A</div>
<div v-else-if="type === 'B'"> B</div>
  • 搭配3
<div v-if="type === 'A'"> A</div>
<div v-else="type === 'C'">  C</div>

4. 列表渲染:v-for 指令

  • 语法:v-for = “xxx in yyy”

yyy:是可迭代的,按照从前往后的顺序迭代,每次迭代都从yyy拿到一个值给xxx。迭代几次就有几个列表标签

  • 作用:基于可迭代的来渲染列表
1. yyy是数组items
  • 写法1:item in yyy
  • 写法2:(item,index) in yyy

yyy[index] === item,第一个参数item表示它是yyy的元素,第二个参数index表示它在yyy的索引值

<ul id="rendering">
  <li v-for="item in items">
    {{item.message }}
  </li>
    
  <li v-for="(item,index) in items">
    {{index}} - {{item.message }}
  </li>  
</ul>
new Vue({
  data() {
    return {
      items: [{ message: 'Foo' }, { message: 'Bar' }]
    }
  }
}).mount('#rendering')
2. yyy 是对象obj
  • 写法1:value in obj
  • 写法2:(value,name) in obj

Object.keys() 的结果遍历,遍历一次得到一个obj的属性。第一个参数name代表这个属性的名字,第二个参数value代表这个属性的值

<ul id="rendering">
  <li v-for="value in myObject">
    {{value }}
  </li>
    
  <li v-for="(value,name) in myObject">
    {{name}} - {{value}}
  </li>  
</ul>
 new Vue({
  data() {
     return {
        myObject: {
            title: 'How to do lists in Vue',
            author: 'Jane Doe',
            publishedAt: '2016-04-10'
        }
     }
  }
}).mount('#rendering')

3.yyy 是字符串str
  • 写法1:value in str
  • 写法2:(value,index) in str

按顺序遍历,str[index] === value,第一个参数value表示它是str的字符,第二个参数index代表value在yyy的索引值

<ul id="rendering">
  <li v-for="value in str">
    {{value }}
  </li>
    
  <li v-for="(value,index) in str">
    {{index}} - {{value}}
  </li>  
</ul>
 new Vue({
  data() {
     return {
       str:"hello"
     }
  }
}).mount('#rendering')
4. yyy 是整数
  • 写法1:n in yyy
  • 写法2:(n,idnex) in yyy

index:是索引,从0开始的,但是n的是从 1 开始的

<div id="range" class="demo">
  <span v-for="(n,index) in 10">{{n}} - {{index}} </span>
    
</div>
嵌套
  • 对于多层嵌套的 v-for,作用域的工作方式和函数的作用域很类似。每个 v-for 作用域都可以访问到父级作用域:
<li v-for="item in items">
  <span v-for="childItem in item.children">
    {{ item.message }} {{ childItem }}
  </span>
</li>
状态管理—key
  • 对于使用v-for指令渲染的列表,Vue会通过key来管理这些列表
  • 对于每个列表元素,key都要是唯一的(key不存在于真实DOM上)

跟虚拟DOM,真实DOM,diff算法有关,下面简单讲解带来的问题,后面再详细讨论

  • 默认模式:key默认用index绑定
<li v-for="item in items"></li>

等价于后者

<li v-for="item in items" :key="index"></li>
  • 自定义模式
<li v-for=" item in items" :key="item.id"></li>
遍历列表时使用index作为key带来的问题
  • Vue动态渲染页面的步骤 (个人的理解)

    1. Vue首先将数据渲染到模板上面(初始化)
    2. 生成虚拟DOM (用于复用)
    3. 将虚拟DOM转为真实DOM
    4. 当Vue发现数据变化时,会根据新数据生成新的虚拟DOM
    5. 将新虚拟DOM与旧虚拟DOM按照一定规则进行比较,找出它们之间的区别,并应用这其中的变化到真实的 DOM 上(这就是diff算法)
  • diff算法怎么比较新虚拟DOM和旧虚拟DOM?

    • key是虚拟DOM的唯一标识
    • diff算法只会在同层级按照一定规则进行比较
    1. 由于生成的虚拟DOM会构成一个DOM树,diff算法会将这新旧两颗DOM树从第一层开始进行同层比较
    • 如果新虚拟DOM的key与旧虚拟DOM的key值相同
      • 如果新虚拟DOM的内容与旧虚拟DOM的内容相同,直接使用旧虚拟DOM对应的真实DOM
      • 如果不同,则生成新的真实DOM,随后替换掉页面中旧虚拟对应的真实DOM
    • 如果新虚拟DOM的key与旧虚拟DOM的key值不同
      • 创建新的真实DOM,随后渲染到页面

这里简单讨论了Vue渲染页面的过程以及diff算法比较新旧DOM树的一些细节,可以发现key是在diff算法对比新旧DOM树时发挥作用,但是在某些情况下会带来一些问题

  • 旧虚拟DOM
<li  key="0"><input type = "text"></li>
<li  key="1"><input type = "text"></li>
<li  key="2"><input type = "text"></li>
<li  key="3"><input type = "text"></li>
  • 生成的真实DOM

在这里插入图片描述

  • 输入数据,但虚拟DOM没变
    在这里插入图片描述
  • 逆序插入数据生成新的虚拟DOM
<li  key="0"><input type = "text"></li>
<li  key="1"><input type = "text"></li>
<li  key="2"><input type = "text"></li>
<li  key="3"><input type = "text"></li>
<li  key="4"><input type = "text"></li>
  • 因修改数据而生成真实DOM
    在这里插入图片描述

  • 可以发现此时生成的真实DOM出问题了,这是由于diff算法的对比规则导致的

这里因为虚拟DOM都是同层的,diff算法按顺序比较,首先比较新虚拟DOM和旧虚拟DOM的的第一个节点,发现这两个DOM的key相同,然后开始比较这个节点的内部节点,发现内容节点不同,但是节点input是相同的,于是拿内容节点生成真实的DOM会替换旧虚拟DOM的内容节点对应的真实DOM,新的真实DOM展示在页面是这样的
在这里插入图片描述

依次比较,直到新虚拟DOM的第五个节点,此时算法发现这个节点不存在于旧虚拟DOM中,于是将第五个节点转成真实DOM,展示在页面是这样的

在这里插入图片描述

总结
  • 会破坏原来顺序的就不要用index作为key的值

5.v-text指令和v-html指令

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script         src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">   </script>
</head>
<body>
  <div id="root">
      <a v-text="name">name</a><br/>
      <a v-html="name">name</a><br/>
  </div>
</body>

<script> 
    new Vue({
        el:'#root',
        data:{
            name:'<h1>hello</h1>',
        }
    })
</script>
</html>
  • v-text指令:用该指令的值替换所在标签的内容
  • v-html指令:用该指令的值替换所在标签的内容,如果该指令的值包含html语法,这部分就按html语法解析

容易导致xss攻击,永远不要在用户提交的内容上使用v-html指令

  • 运行结果如图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1Hoss31-1652154741617)(images/图一.png)]

6.v-once指令和v-pre指令

  • v-once指令的作用:其所在节点在初次动态绚染后就不可更改,用于优化性能

  • v-pre指令的作用:用来跳过没有使用指令语法,插值语法的节点的编译过程,加快编译

  • 案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
  <div id="root">
      <h2>n:{{n}}</h2>
      <h2 v-once>n:{{n}}</h2>
      <button @click="n++">n++</button>
      <h2 v-pre>{{name}}</h2>
      <h2 v-pre>hello</h2>
  </div>
</body>

 <script>
     
    new Vue({
        el:'#root',
        data:{
            name:'<h1>hello</h1>',
            n:0
        }
    })
 </script>
</html>

7.v-cloak指令(没有值)

  • 使用css + v-cloak可以解决网速慢时页面展示出{{xxx}}的问题

本质是一个特殊属性:Vue实例创建对象并接管容器后,会删除v-cloak属性

  • 案例
<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <title>Document</title>
  
   <style>
       [v-cloak]{
           display:none,
       }
   </style>
</head>

<body>
 <div id="root">
     <a v-cloak>{{name}}</a>     
 </div>
</body>

<script>
   new Vue({
       el:'#root',
       data:{
           name:'<h1>hello</h1>'
       }
   })
</script>
</html>

8.自定义指令

局部自定义指令
  • 函数式

  • 函数接收的可选参数(内部出现的this执行windows)

    • element:使用该指令的元素
    • bind:绑定的一些相关信息
    • vNode:当前的虚拟dom节点
    • oldvNode:上一个虚拟dom
  • 函数(如print函数)什么时候调用:

    • 指令与元素成功绑定时 (此时页面还没加载出来)

    绑定之后,解析模板并加载到页面

    • 指令所在的模板重新解析时(此时页面已加载出来)
const vm = new Vue({
    name:"home",
    data:{
          n:1
    },
    directives: {
       //定义v-foucus指令
       focus(element,bind,vNode,oldvNode){
            console.log(element,bind,vNode,oldvNode)
       },
        //定义v-printMessage指令   
        //多个单词的写法
       `print-message`(){
             console.log("hello")
       }
    }
})

vm.$mount("#demo")
  • 示例
<div id="demo">
   <span v-print-message>hello</span>
   <span v-focus>hello</span>
   <span v-focus="n">hello</span> 
</div>
  • 对象式
  • 指令中可写的特殊函数(内部出现的this执行windows)
    • bing函数:当指令与元素成功绑定时执行
    • inserted函数:指令所在的元素被插入页面时执行
    • update函数:指令所在的模板被重新解析时调用
  • 这些函数接收的可选参数
    • element:使用该指令的元素
    • bind:绑定的一些相关信息
    • vNode:当前的虚拟dom节点
    • oldvNode:上一个虚拟dom
const vm = new Vue({
    name:"home",
    data:{
          n:1
    },
    directives: {
        focus: {
            
        
            bind(element,bind){
                console.log('bind')
            },
          
            inserted(element,bind){
                console.log('inserted')
            },
           
            update(){
                console.log('update')
            }
        }
    }
})

vm.$mount("#demo")
全局自定义指令
  • 函数接收的参数,调用时机与定义局部指令一致

  • 函数式

    • Vue.directives(指令名,回调函数)
Vue.directives(“find”,function(element,bind){
})
  • 对象式
    • Vue.directives(指令名,配置对象)
Vue.directives(“find”,{
            bind(element,bind){
                console.log('bind')
            },
          
            inserted(element,bind){
                console.log('inserted')
            },
           
            update(){
                console.log('update')
            }
})
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

柳衣白卿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值