轻松掌握纯前端js框架---VUE Ⅱ

能力配不上野心,是全部烦扰的根源。这个世界是公平的,你要想获得,就得学会付出和坚持。每一个人都是经过本身的努力,去决定生活的样子。
复制代码

本期主要内容

  1. 指令:
  2. 双向绑定:
  3. 绑定样式:
  4. 自定义指令:

一. 指令:

  1. 根据数组内容,反复建立多个相同结构的元素: v-forjavascript

    (1). <要反复建立的元素 v-for="(value, i ) of 数组/对象/字符串">html

    (2). 原理: 当new Vue()首次扫描到这里时,或依赖的数组内容发生变化时:vue

    a. 自动遍历of后的数组或对象...java

    b. 每遍历一个成员,就数组

    1). 将成员的值交给of前的value变量,
     2) 将成员的下标位置交给of前的i变量
    复制代码

    c. 反复建立v-for所在HTML元素,并将value和i的值替换到元素中可能发生变化的位置.浏览器

    d. 在v-for所在的当前元素上以及当前元素的全部子元素中,均可以用value和i变量进行绑定。bash

(3). 强调:app

a. v-for必须写在要反复生成的元素上,而不能写在父元素上: 

	好比: 反复生成一个ul下的多个li元素,v-for应该写在子元素li上
	
b. of前的变量(value,i)可随意更名!但第一个变量始终接元素值,第二个变量始终接下标

(4). 其实vue中的v-forof,统一了js中的forof和forin的功能!既可遍历数字下标,又可遍历自定义下标。
复制代码

(5). 问题: 由于v-for反复生成的多个HTML元素,除了内容不一样以外,元素自己毫无差异!致使,万一依赖的数组中某个元素发生变化,v-for没法精确的找到具体应该修改哪一个HTML元素副本。因此v-for选择最笨的方法,将全部元素删掉,从新遍历数组,从新建立全部副本——效率低框架

(6). 解决: 凡是用v-for时,都必须同时绑定:key="下标"属性 结果: 每一个HTML元素副本上都有一个key="下标"属性。当对数组中某一个元素执行操做时,vue会根据下标找到对应key="下标"的一个元素,只修改这一个元素,不影响其余元素。—— 效率高!函数

(7). 总结: 鄙视: 为何v-for必须加:key?

a. 避免在修改某一个数组成员时,重建全部HTML元素副本
b. 若是加了:key,每次只须要修改一个数组元素对应的一个HTML元素副本便可——效率高
复制代码

(8). 示例: 使用v-for遍历数组和对象

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <ul>
      <!--由于要根据数组tasks的内容反复生成多个相同结构的li元素,因此应该在li元素上用v-for-->
      <li v-for="(value,i) of tasks" :key="i">
        <!--由于反复生成的内容中须要动态得到每一个元素值和下标,因此,能够用of前的变量value和i用于绑定语法中动态生成内容-->
        {{i+1}}. {{value}}
      </li>
    </ul>
    <!--想遍历出lilei对象中每一个属性的属性名和属性值-->
    <ul>
      <li v-for="(value,key) of lilei" :key="key">{{key}}: {{value}}</li>
    </ul>
  </div>
  <script>
    new Vue({
      el:'#app',
      data:{
        //有一个任务列表,但愿展示到页面上
        tasks:["吃饭","睡觉","打亮亮"],//.length=3
        //       0      1      2
        lilei:{
          sname:"Li Lei",
          sage:11,
          className:"初一2班"
        }
      }
    })
  </script>
</body>
</html>
运行结果: 

复制代码

9). 其实: v-for还会数数:仅根据一个数字,就可反复生成指定数量的HTML元素副本,且从1开始数数,一直数到给的数字为止

a. <要反复生成的元素 v-for="i of 数字">
b. 原理: 当new Vue()首次扫描到这里时,或依赖的数值发生变化时:
	1). 数字是几,就会反复建立几个HTML元素副本
	2). 每次建立副本时,都会将本次数到的数字保存到of前的变量中
	3). 在当前元素及其子元素中变量i,可用于绑定。
复制代码

(10). 示例: 使用v-for生成分页按钮

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <style>
    #pages{ list-style: none; }
    #pages>li{
      float:left;
      padding:5px 10px; 
      border:1px solid #aaa;
      margin:0 5px;
    }
  </style>
</head>
<body>
  <div id="app">
    <!--但愿总页数是几,就反复生成几个分页分页按钮-->
    <ul id="pages">
      <li v-for="i of pageCount" :key="i">{{i}}</li>
    </ul>
  </div>
  <script>
    new Vue({
      el:"#app",
      data:{
        pageCount:5,//分页时都会有一个变量保存总页数
      }
    })
  </script>
</body>
</html>
运行结果: 

复制代码

  1. 绑定事件: v-on

    (1). 标准: <元素 v-on:事件名="事件处理函数()">

    (2). 等效于: DOM中的<元素 on事件名="事件处理函数()">

    (3). 重要差异: VUE中事件处理函数中的this,再也不指向当前触发事件的元素。而是指向当前整个new Vue()对象!

    (4). 简写:

    a. "v-on:"可用"@"代替: <元素 @事件名="事件处理函数()">

    b. 若是事件处理函数没有任何实参值,则能够省略():<元素@事件名="事件处理函数">

    (5). 其实: vue中的事件处理函数能够传参!

    a. <元素 @事件名="事件处理函数(实参值列表)">
      methods:{
    	  事件处理函数(形参列表){ ... }
      }
    复制代码

    b. 示例: 点哪一个div,哪一个div喊谁疼!

    <!DOCTYPE html>
    复制代码
Document
运行结果:
```
复制代码

(6). 其实: 在vue中也可得到事件对象: 2种

a. 无需传其它实参值,只但愿得到事件对象时:
	1). 同DOM: 事件对象老是默认做为事件处理函数的第一个实参值自动传入
	2). <元素 @事件名="事件处理函数">
		methods:{
			事件处理函数(e){ ... }
		}
	3). 问题: 若是须要同时传入实参值和得到事件对象,实参值和事件对象e传入的位置就会撞车!
	<元素 @事件名="事件处理函数(实参值)">
                     event
		methods:{
			事件处理函数(e){ ... }
		}
	4). 错误的解决1: 在methods中在事件处理函数中e以前多加一个形参变量
	<元素 @事件名="事件处理函数(实参值)">
                     event
		methods:{
			事件处理函数(形参1, e){ ... }
		}
		由于event对象,默认只能传给第一个形参变量,不会给以后的其它形参
	5) 错误解决2: methods中交换事件处理函数的两个形参变量的顺序
	<元素 @事件名="事件处理函数(实参值)">
                     event
		methods:{
			事件处理函数(e, 形参1){ ... }
		}
		由于第一个实参值,不会聪明到自动给第二个形参变量,依然给第一个形参,依然会和event发生冲突
	6). 示例: 鄙视题: vue中如何得到鼠标位置: 
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <style>
    #app>div{
      width:300px; 
      height:100px;
    }
    #app>div:hover{
      box-shadow:0 0 5px red
    }
  </style>
</head>
<body>
  <div id="app">
    <!--点哪一个div的某个位置,就喊某个为疼!-->
    <div id="d1" style="background-color:#aaf" @click="say"></div>
    <div id="d2" style="background-color:#ffa" @click="say"></div>
  </div>
  <script>
    new Vue({
      el:"#app",
      data:{},
      methods:{
        //由于想得到鼠标点击的位置,必须加形参e
        //event
        //  ↓
        say(e){
          alert(`${e.offsetX},${e.offsetY}位置 疼! `)
        }
      }
    })
  </script>
</body>
</html>
运行结果:

复制代码

b. 若是同时传入实参值和事件对象:借助于vue一个关键词$event

DOM event
							         先↓
<元素 @事件名="事件处理函数(实参值,  $event)">

		methods:{
			事件处理函数(形参1, e){ ... }
		}
	说明: $event和实参值能够交换位置。$event不管在实参列表中第几个位置,均可先得到事件对象event。不受位置影响!
复制代码

c. 示例: 鄙视题: 若是同时传入自定义实参值和事件对象:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
  <style>
    #app>div{
      width:300px; 
      height:100px;
    }
    #app>div:hover{
      box-shadow:0 0 5px red
    }
  </style>
</head>
<body>
  <div id="app">
    <!--若是既须要传入实参值,又须要得到事件对象-->
    <!--                 DOM event-->
    <!--                    先 ↓  -->
    <div id="d1" @click="say($event,'d1')" style="background-color:#aaf" ></div>
    <!--                 DOM event-->
    <!--                    先 ↓  -->
    <div id="d2" @click="say($event,'d2')" style="background-color:#ffa" ></div>
  </div>
  <script>
    new Vue({
      el:"#app",
      data:{},
      methods:{
        //由于界面上调用事件处理函数时,传入了两个实参,因此methods中定义事件处理函数时,也必须定义两个形参对应
        say(e, id){
          alert(`${id}${e.offsetX},${e.offsetY}位置 疼! `)
        }
      }
    })
  </script>
</body>
</html>
运行结果: 

复制代码

  1. 防止用户短暂看到{{}}:

    (1). 问题: 若是网速很差,js代码下载较慢,用户可能短暂看到页面上的{{}}语法!——尴尬!

    (2). 解决: 2种方法

    a. 用v-cloak属性:

    1). 2步:
     i. 先在页面上统一位置定义一个属性选择器: 
     [v-cloak]{ display:none } 意为: 凡是带有v-cloak属性的元素,都默认隐藏
     斗篷/幕布
     ii. 在网页中带有{{}}内容的元素上添加v-cloak属性,不须要任何属性值
     2). 结果: 
     i. 若是网速慢, new Vue()所在的js暂时没有下载下来时,v-cloak选择器起做用,带有v-cloak和{{}}的元素暂时隐藏
     ii. 当new Vue()所在的js文件,下载完成后,new Vue()自动找到全部v-cloak属性,自动移除这些元素上的v-cloak属性。这些带有{{}}的元素就显示出来了!
     3). 强调: v-cloak属性是vue内置的指令名,不要随意修改!
    复制代码

    b. 用v-text指令代替{{}}:

    1). 1步: <元素 v-text="变量或js表达式">    </元素>
     2). 原理: 当new Vue()首次扫描到这里或依赖的变量发生变化时
     	vue都会先计算""中js表达式的结果,而后用结果代替元素的内容
     3). 为何能够屏蔽{{}},由于根本就没用{{}}。
     4). 问题: {{}}的好处在于能够随意和其它写死的字符串拼接出一个新的字符串显示。可是用v-text,则没法将写死的字符串和变量或表达式随意拼接。
     5). 解决: 在v-text中将写死的字符串和变量或表达式随意拼接,必须用模板字符串(反引号和${})
     <元素 v-text="`xxxx ${变量或js表达式}`">    </元素>
    复制代码

    (3). 示例: 分别使用v-text和v-cloak解决短暂看到{{}}的问题:

    <!DOCTYPE html>
    复制代码
Document

用户名:{{uname}}

运行结果:

2s后才看到

```
复制代码
  1. 要绑定的内容是HTML片断: v-html

    (1). 问题: 若是用{{}}或v-text绑定一段HTML片断,则不会将要绑定的内容交给浏览器解析,而是保持原样显示在页面上——不是咱们想要的

    (2). 为何: {{}}和v-text底层其实至关于DOM中的.textContent

    (3). 解决: 从此,只要绑定一段HTML片断,都要用v-html代替v-text和{{}}

    (4). 为何: v-html底层至关于DOM中的.innerHTML

    <元素 v-html="变量或js表达式"> </元素>

    (5). 原理: v-html会先将要绑定的内容交给浏览器解析,而后将解析后的能够给人看的内容替换元素的内容显示出来。

    (6). 示例: 分别使用{{}}、v-text和v-html绑定HTML片断内容

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>{{html}}</h3>
    <h3 v-text="html"></h3>
    <h3 v-html="html"></h3>
  </div>
  <script>
    new Vue({
      el:"#app",
      data:{
        html:`来自&lt;&lt;<a href="javascript:;">新华社</a>&gt;&gt;的消息`
      }
    })
  </script>
</body>
</html>
运行结果: 

复制代码

  1. 只在首次加载时绑定一次:

    (1). 问题: 有些界面上显示的内容,只在首次加载时更新一次。以后几乎不会改变!若是这种元素也包含在虚拟DOM树中,无形中就增大了虚拟DOM树,可能影响遍历的速度

    (2). 解决: 让这种元素只在首次加载时绑定一次,并且不加入虚拟DOM树中。

    (3). 如何: <元素 v-once></元素>

    (4). 原理: 凡是带有v-once的元素,只在首次加载时绑定一次,以后即便变量发生变化也不会改变。由于v-once的元素根本就没有加入到虚拟DOM树。

    (5). 优势: 减小了虚拟DOM树中的内容,加快遍历的速度

    (6). 示例: 使用v-once绑定页面加载完成时间

    <!DOCTYPE html>
    复制代码
Document

页面加载完成时间(一次性): {{time}}

当前系统时间(反复屡次): {{time}}

运行结果:
```
复制代码

  1. 防止内容中{{}}被编译: v-pre

    (1). 特殊状况:在元素内容中刚巧包含{{}},可是不想被vue编译,只是想原样显示出来

    (2). <元素 v-pre>xxx{{xxx}}xxx</元素>

    (3). 结果: vue不会将内容中的{{}}解析为变量或js表达式,而是原样显示在页面上。

    (4). 示例: 防止内容中的{{}}被编译:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3 v-pre>Vue框架用{{变量名}}方式标记页面中可能发生变化的位置</h3>
  </div>
  <script>
    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>
运行结果: 

复制代码

二. *****双向绑定:

  1. 问题: 以上12种绑定方式都没法得到用户在页面上文本框中输入的新值!

  1. 缘由: 由于前12中绑定或指令都是单向绑定:

    (1). 单向绑定: 只能将程序中的变化,自动送到界面去,没法将界面上用户所作的修改,反向更新回程序中的变量中。(只能从Model->View,不能从View->Model)

  1. 解决: 从此只要但愿随时得到用户在页面上表单元素中所作的修改时,都要用双向绑定

    (1). 双向绑定: 既能将程序中的变化,自动送到界面去,又能将界面上用户所作的修改,反向更新回程序中的变量中。(既能从Model->View,又能从View->Model)

  2. 如何: 一般用于绑定表单元素,由于只有表单元素,用户才能在页面上修改! <表单元素 v-model:value="自定义变量">

data:{
		自定义变量: 初始值
	}
	
复制代码
  1. 示例: 点按钮,得到文本框中输入的关键词,执行搜索操做
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <!--界面中哪一个可能发生变化? 文本框的内容可能发生变化
      由于文本框的内容是value属性,要绑定value属性值,应该用:绑定,自定义变量名为keywords-->
    <!--可是,由于:value只能单向绑定(M->V),不能双向绑定(V->M),因此要改成v-model:value,才能双向绑定(V->M)-->
    <!--点哪里可能触发查找事件? button-->
    <input v-model:value="keywords"><button @click="search">百度一下</button>
  </div>
  <script>
    new Vue({
      el:"#app",
      //既然页面上须要一个keywords变量,data中就应该定义一个keywords变量支持页面
      data:{
        keywords:"mac"//开局是空字符串
      },
      methods:{
        //由于页面上须要一个事件处理函数search(),因此methods中就要定义一个search()函数
        search(){
          //若是keywords中收到的关键词不是空字符串,则执行查找操做
          if(this.keywords.trim()!==""){
            console.log(`查找 ${this.keywords.trim()} 相关的内容...`)
          }
        }
      }
    })
  </script>
</body>
</html>
运行结果:

复制代码

  1. 双向绑定原理: 在单向绑定原理(访问器属性+虚拟DOM树)基础上,又自动为表单元素绑定了onchange事件

    onchange事件是DOM中经常使用事件,意为当内容发生改变时自动触发!

  2. 示例: 使用@change事件和DOM e.target,模拟双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <!--当文本框内容发生改变时,自动得到文本框中的新值,保存到变量keywords中-->
    <input :value="keywords" @change="change"><button @click="search">百度一下</button>
  </div>
  <script>
    new Vue({
      el:"#app",
      //既然页面上须要一个keywords变量,data中就应该定义一个keywords变量支持页面
      data:{
        keywords:"mac"//开局是空字符串
      },
      methods:{
        //由于页面上须要一个事件处理函数search(),因此methods中就要定义一个search()函数
        search(){
          //若是keywords中收到的关键词不是空字符串,则执行查找操做
          //if(this.keywords.trim()!==""){
            console.log(`查找 ${this.keywords.trim()} 相关的内容...`)
          //}
        },
        //如何得到当前元素的内容: DOM e.target
        change(e){
          //            当前文本框的内容
          this.keywords=e.target.value;
        }
      }
    })
  </script>
</body>
</html>
运行结果: 

复制代码

  1. 问题: 有些表单元素用户在修改时value是固定不变的!改的是其余属性:

    好比: 性别:

<input type="radio" value="1" name="sex">男
<input type="radio" value="0" name="sex">女
复制代码
  1. 解决: 分析,用户操做这些元素时,到底该的是哪一个属性?

    1). 好比: 用户选中或不选中radio,改的是radio的checked属性!

    2). 因此: v-model应该绑定在checked属性上

<input type="radio" value="固定值" name="分组名" v-model:checked="变量名">
复制代码

3). 原理:

i. 开局: 将程序中的变量值显示到页面上:radiov-model:checked="变量名"v-model会用变量值和当前radio的value作比较,若是变量值等于当前radio的value,则当前radio选中。不然,若是变量值不等于radio的value,则当前radio不选中

ii. 当用户切换了radio的选中状态时:

若是当前radio选中,则v-model自动将当前radio的value值传到程序中保存在data中的变量里。若是当前radio未选中,则v-model什么也不作

  1. 示例: 在vue中选择性别:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="js/vue.js"></script>
</head>
<body>
  <div id="app">
    <h3>您的性别是: {{sex}}</h3>
    <!--由于用户选择性别时同时改变两个radio的checked属性,因此两个radio上都要写v-model:checked=xxx
        又由于不管用户点哪一个input,修改的都是性别这一个属性值,因此两个radio绑定时都绑定sex一个变量-->
    性别: 
    <label><input type="radio" value="1" name="sex" v-model:checked="sex">男</label>
    <label><input type="radio" value="0" name="sex" v-model:checked="sex">女</label>
  </div>
  <script>
    new Vue({
      el:"#app",
      //由于页面上只须要一个变量sex标记性别
      data:{
        sex:1, //开局为1 表示男
      }
    })
  </script>
</body>
</html>
运行结果: 


复制代码

相关文章
相关标签/搜索