輕鬆掌握純前端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>
運行結果: 


複製代碼

相關文章
相關標籤/搜索