萬字血書Vue—Vue語法

辜負寒徹骨發表於2023-03-17

模板語法

插值語法

Mustache插值採用{{ }},用於解析標籤體內容,將Vue例項中的資料插入DOM中

 <h1>Hello {{name}}</h1>

指令語法

指令用於解析標籤,是vue為開發者提供的一套模板語法輔助開發者渲染頁面的基本結構

(指令是vue開發中最基礎、最常用、最簡單的知識點)(支援繫結簡單的資料值之外,還支援js表示式運算)

內容渲染指令

1、v-text=" " 會覆蓋元素內預設的值、無法寫HTML標籤語句

2、{{ }} 插值表示式(Mustache) 不會覆蓋元素中預設的內容

3、v-html 可以渲染包含HTML標籤的字串

v-html有安全性問題,在網站上動態渲染任意HTML是非常危險的,容易導致XSS攻擊;永遠不要再使用者提交的內容上使用v-html

屬性繫結指令

v-bind: 為元素的屬性動態繫結屬性值

屬性:placeholder、src等

簡寫::

<a v-bind:href="url">點選跳轉</a>
<a :href="url">點選跳轉</a>
事件繫結指令

v-on: 為DOM元素繫結事件監聽

v-on:click=” “、v-on:input、v-on:keyup

事件處理函式,需要在methods節點中進行宣告

簡寫:@、如果事件處理函式的程式碼足夠簡單,只有一行程式碼,則可以簡寫到行內

事件物件event
<body>
    <div id="app">{{username}}</div>
    <button @click="addcount($event,88)">
        點選我
    </button>

    <script src="vue.js"></script>
    <script>
        const vm=new Vue({
            el:'#app',
            data:{
                username:'zs',
                count:0
            },
            methods:{
                addcount(e,88){
                    const nowBgColor =e.target.style.backgroundColor
                    console.log(nowB gColor)
                    this.count+=1
                }
            }
        })
    </script>
</body>

繫結事件並傳參,使用() 小括號,但會佔用event的位置

$event是vue提供的特殊變數用於佔位,用來表示原生事件引數物件event,使用e接受

事件修飾符

vue提供事件修飾符,來輔助程式設計師更方便的對事件的觸發進行控制

  • .stop阻止事件冒泡()裡到外

  • .prevent 阻止預設行為()比如阻止跳轉

  • .capture捕獲模式觸發當前事件處理函式(外到裡)

  • .self只有在event.target是當前元素自身時觸發事件處理函式

  • .once繫結的事件只觸發一次

  • .passive事件的預設行為立即執行,無需等待事件回撥執行完畢

按鍵修飾符

監聽鍵盤事件時,我們經常需要判斷詳細的按鍵,此時可為鍵盤相關的事件新增按鍵修飾符

  • .enter、.delete、.esc、.space、.tab(特殊:只適用於keydown)、.up、.down、.left、.right
  • 系統修飾符(用法特殊):ctrl、alt、shift、mta 配合keyup使用:按下按鍵的同時需要再按下其他鍵,隨後事件才被觸發;keydown正常觸發事件
  • 也可以使用keyCode去指定具體的按鍵(不推薦)
  • Vue.config.keyCodes.自定義鍵名=鍵碼 可以去定製按鍵別名
雙向繫結指令

v-model 在不操作DOM的情況下,快速獲取表單資料(只能配合表單元素一起使用)

<input type="text" v-model:value="username"/>
<input type="text" v-model="username"/>
v-model 指令的修飾符

方便使用者對輸入的內容進行處理

  • .number自動將使用者輸入值轉化為數值
  • .trim 自動過濾使用者輸入的首尾空白字元
  • .lazy 在change時更新而非input時更新(不實時更新,文字框失去焦點更新)
條件渲染指令

按需控制DOM的顯示和隱藏

v-if =" " 動態建立或移除DOM元素,有更高的切換開銷(重繪和迴流)

v-else-if =" "v-else =" "

v-show=" " 動態為元素新增或移除display樣式,有更高的初始渲染開銷。

列表渲染指令

v-for=" " 輔助開發者基於一個陣列來迴圈渲染相似的UI結構

特殊語法:item in items

<body>
   
    <div id="root">
        <!-- 遍歷陣列 -->
        <ul>
            <li v-for="item in persons" :key="item.id">
                {{item.id}}-{{item.name}}-{{item.age}}
            </li>
        </ul>
        <!-- 遍歷物件 -->
        <ul>
            <li v-for="(value,key) of cars" :key="key">
                {{key}}-{{value}}
            </li>
        </ul>
        <!-- 遍歷字串 -->
        <ul>
            <li v-for="(char,index) of str" :key="index">
                {{index}}-{{char}}
            </li>
        </ul>
        <!-- 遍歷指定次數 -->
        <ul>
            <li v-for="(number,index) of 5" :key="index">
                {{index}}-{{number}}
            </li>
        </ul>

    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;
        const vm=new Vue({
            el:'#root',
            data:{
                persons:[
                    {id:'001',name:'張三',age:18},
                    {id:'002',name:'李四',age:17},
                    {id:'003',name:'王五',age:42},
                ],
                cars:{
                    name:'Audi',
                    price:"70W",
                    color:"black"
                },
                str:"hello"

            }
        })
   
    </script>
    
</body>
for in和for of

for in一般遍歷物件,不建議遍歷陣列。遍歷陣列請使用for of或forEach。

v-for中的索引

(item,index) in items

注:v-for中的item項和index索引都是形參,任意命名

key作用和原理

當列表的資料變化(新增、刪除)時,vue會盡可能複用已存在的DOM元素,從而提升渲染的效能,但這種效能最佳化策略會導致有狀態的列表無法被正確更新,key的使用將減少不必要的DOM操作,提高更新效率。

解釋:

Vue根據初始資料生成初始虛擬DOM(Vnodes),將虛擬DOM轉為真實DOM,使用者新增新的資料,產生新虛擬DOM(Vnodes),此時將兩份虛擬DOM根據key進行對比(diff 演算法),如果對比一樣的直接複用,將之前的真實DOM直接渲染;不一樣的無法複用,將其生成真實DOM。

  • 如果使用index作為key,diff對比時會完全錯位,所有節點都無法複用,效率降低。
  • 如果不指定key時,vue自動使用遍歷時的索引值index作為key。

為了給vue一個提示,以便它能跟蹤每個節點的身份,需要為每項提供一個唯一的key屬性

image

image

注:

  • key只能是字串或數字型別

  • key的值必須具有唯一性

  • 建議把資料項id屬性的值作為key的值,將index的值作為key的值沒有任何意義https://blog.csdn.net/z591102/article/details/106682298/)

  • 建議使用v-for時一定要指定key的值(提升效能,防止列表狀態紊亂)

  • 但不存在對資料的操作,僅是渲染列表用於展示,使用index作為key沒有問題

image

其他內建指令

v-cloak沒有值,配合CSS,解決網速慢、伺服器響應慢時未經解析的模板渲染到頁面上,Vue例項建立並接管容器後,會刪掉該屬性。

[v-cloak]:{
    display:none;
}

v-once沒有值,記錄初始值,在初次動態渲染後,就視為靜態內容,以後資料的改變不會引起v-once所在結構的更新,可以用於效能最佳化。

v-pre沒有值,跳過其所在節點的編譯過程,可以用它跳過:沒有使用指令語法、插值語法的節點,會加快編譯。

自定義指令

本質:將原生操作DOM進行二次封裝。

<body>
   
    <div id="root">
        <!-- v-big放大10倍 -->
        <h2>當前的n值是:<span v-text="n"></span></h2>
        <h2>放大10倍後的n值是:<span v-big="n"></span></h2>
        <button @click="n++">點位n++</button>
        <hr>
        <!-- v-fbind在v-bind基礎上,自動獲得焦點 -->
        <input type="text" v-fbind:value="n">
    </div>
    <script type="text/javascript">
        Vue.config.productionTip = false;
        const vm=new Vue({
            el:'#root',
            data:{
               n:0,
            },
            directives:{
                //函式式
                //何時會被呼叫:1、指令和元素成功繫結;2、指令所在的模板被重新解析時
                big(element,binding){
                    element.innerText=binding.value*10
                },
                //錯誤寫法:
                fbind(element,binding){
                    element.value=binding.value
                    element.focus()//.focus()呼叫時機不對,此時input還未被插入頁面
                },
                //物件式
                fbind:{
                    //指令與元素成功繫結時呼叫
                    bind(element,binding){
                        element.value=binding.value
                    },
                    //指令所在元素被插入頁面時呼叫
                    inserted(element,binding){
                        element.focus()
                    },
                    //指令所在模板被重新解析時呼叫
                    update (element,binding) {
                        element.value=binding.value
                    },
                }

            },
        })
   
    </script>
</body>

注意:

  • 命名多個單詞使用-分隔;
  • 指令中this的指向是window
  • 自定義指令預設都是區域性指令,全域性寫法:Vue.directive

計算屬性

計算屬性本質上就是一個function函式,它可以實時監聽data中資料的變化,並return一個計算後的新值,供元件渲染DOM時使用。

開發者需要以function函式的形式宣告到元件的computed節點

<template>
  <div>
    <input type="text" name="" id="" v-model.number="count">

    <p>{{count}} 乘以2的值為:{{plus}}</p>//必須當做普通屬性使用
  </div>
</template>

<script>
export default {
    name:'MyCount',
    data(){
        return{
            count:1,
        }
    },
    //必須定義在computed節點
    computed:{
        //必須是一個function函式
        plus(){
            //必須具有返回值
            return this.count*2
        }
        
        //相當於
        
        plus:{
        //當讀取plus,get會被呼叫,且返回值作為plus的值
        //get何時被呼叫?1、初次呼叫plus;2、所依賴的資料發生變化
        get(){
            return this.count*2
        }
      }
    }

}
</script>

側重於得到一個計算的結果,必須有return返回值

計算屬性(computed)vs方法(methods):

相對於方法,計算屬性會快取計算結果,只有計算屬性的依賴項發生變化時,才會重新進行運算,因此計算屬性的效能會更好。

watch偵聽器

watch偵聽器允許開發者監視資料的變化,從而針對資料的變化做特定的操作

開發者需要在watch節點之下,定義自己的偵聽器

<script>
export default {
    name:'MyCount',
    data(){
        return{
            username:'',
        }
    },
   watch:{
       //當username發生改變時,呼叫 handler
       username:{
           handler(newVal,oldVal){
             console.log(newVal,oldVal) 
           }  
       }
      //簡寫
       username(newVal,oldVal){
           console.log(newVal,oldVal)     
       }       
   }
  
   }
</script>
<body>
    <div id="app">{{username}}</div>
    #匯入指令碼檔案
    <script src="vue.js"></script>
    <script>
        const vm=new Vue({
            data(){
            return{
                   username:'zs'
            }
            }
        })
        vm.$mount=('#app')//掛載
        vm.$wtach('username',{ //第二種寫法
            handler(newVal,oldVal){
                console.log(newVal,oldVal)
            }
        })
        //簡寫
        vm.$wtach('username',function(newVal,oldVal){
            console.log(newVal,oldVal)            
        }
        })        
       
    </script>
</body>

應用場景

使用watch檢測使用者名稱是否可用,監聽username值得變化,並使用axios發起ajax請求,檢測當前輸入的使用者名稱是否可用

<script>

import axios from 'axios'

export default {
    name:'MyCount',
    data(){
        return{
            username:'',
        }
    },
 watch:{
    async username(newVal,oldVal){
        console.log(newVal,oldVal)
        const {data:res}=await axios.get('https://www.escook.cn/api/finduser'+newVal)
        //await簡化promise例項物件為資料
        console.log(res)
    }
 }

}
</script>
immediate選項

預設元件在初次載入完畢後不會呼叫watch偵聽器,如果想讓watch偵聽器立即被呼叫,則需要使用immediate選項

<script>

import axios from 'axios'

export default {
    name:'MyCount',
    data(){
        return{
            username:'',
        }
    },
 watch:{
//不能直接定義成方法,要讓監聽的資料指向一個配置物件
  username:{
    async handler(newVal,oldVal){
     const {data:res}=await axios.get('https://www.escook.cn/api/finduser'+newVal)
        //await簡化promise例項物件為資料
        console.log(res)
},
      //立即觸發watch偵聽器
      immediate:true,
      
 }
 }

}
</script>
deep選項

當watch偵聽的是一個物件,如果物件中的屬性值發生了變化,則無法被監聽到,需要使用deep選項偵聽所有屬性的變化。

<script>

import axios from 'axios'

export default {
    name:'MyCount',
    data(){
        return{
            username:'',
        }
    },
 watch:{
//不能直接定義成方法,要讓監聽的資料指向一個配置物件
  username:{
    async handler(newVal,oldVal){
     const {data:res}=await axios.get('https://www.escook.cn/api/finduser'+newVal)
        //await簡化promise例項物件為資料
        console.log(res)
},
      deep:true,//監視多級結構(物件)中所有屬性的變化
 }
 }

}
</script>

監視多級結構(物件)中單個屬性的變化

<script>

import axios from 'axios'

export default {
    name:'MyCount',
    data(){
        return{
            info:{username:'zs',password:'123456'}
            
        }
    },
 watch:{
//不能直接定義成方法,要讓監聽的資料指向一個配置物件
  'info.username':{//只想監聽info.username的屬性變化
    async handler(newVal,oldVal){
     const {data:res}=await axios.get('https://www.escook.cn/api/finduser'+newVal)
        //await簡化promise例項物件為資料
        console.log(res)
},
   
      deep:true,
 }
 }

}
</script>

計算屬性vs偵聽器

  • computed能完成的功能,watch都可以完成,都能完成的,優先使用computed。
  • watch可以完成的,computed不一定能完成,例如watch可以處理非同步任務
  • 計算屬性和偵聽器側重的應用場景不同。
  1. 前者側重監聽多個值的變化,最終計算返回一個新值

  2. 後者側重於單個資料的變化,最終執行特定的業務處理,不需要任何返回值

兩個原則:

  • Vue所管理的函式,最好寫成普通函式,這樣this的指向才是vm或元件例項物件,否則指向window。
  • 所有不被Vue所管理的函式(定時器的回撥函式、ajax的回撥函式、Promise的回撥函式),最好寫成箭頭函式,這樣this的指向才是vm或元件例項物件,否則指向window。

繫結樣式

繫結class樣式

<!--字串寫法,適用於樣式的類名不確定,需要動態指定-->
<h1 class="basic" :class:"className">Hello World!</h1>
<!--陣列寫法,適用於樣式的個數和類名都不確定-->
<h1 class="basic" :class:"classArr">Hello World!</h1>
<!--物件寫法,適用於樣式的個數和類名都確定,但要動態覺得用不用-->
<h1 class="basic" :class:"classObj">Hello World!</h1>

繫結style樣式

<!--動態指定-->
<h1 class="basic" :style="{fontSize: fsize+'px';}">Hello World!</h1>
<h1 class="basic" :style="styleObj">Hello World!</h1>
<h1 class="basic" :style="[styleObj1,styleObj2]">Hello World!</h1>

過濾器

(Vue3.x廢棄,用計算屬性、方法代替)

什麼是過濾器?

過濾器(Filters)常用於文字的格式化,本質是一個函式

過濾器應該被新增到js表示式的尾部,由“管道符”進行呼叫

  • 用於插值表示式
  • 用於v-bind屬性繫結

定義(區域性)過濾器

在建立vue例項期間,可以在filters節點中定義過 濾器

私有和全域性過濾器

私有過濾器:只能在被vm例項控制的區域下控制

如果想在多個vue例項之間共享過濾器,則可以按照如下格式宣告全域性過濾器:

 <script>
        vue.filter('capitalize',(str)=>{
            return str.charAt(0).toUpperCase() + str.slice(1)+'--'
        })
        new Vue...
</script>

注:如果二者衝突以私有過濾器為準,就近原則

連續呼叫多個過濾器

過濾器可以串聯的地呼叫

{{message | capitalize | maxlength}

過濾器傳參

過濾器本質是js函式,第一個引數永遠是管道符前面的值,第二個引數開始才是arg1、arg2...

{{message | filterA(agr1,arg2)}
 
vue.filter('filterA',(msg,arg1,aarg2)=>{})

過濾器的相容性

在vue3.x版本中已經剔除了過濾器相關功能,可以使用計算方法或屬性來代替

相關文章