vue系列:Vue核心概念及特性 (一)

大家好,我是前端嵐楓,一枚二線城市的程序媛,下半年對於我們來說是比較特殊的幾個月,7月底,鄭州出現好多年不遇的水災,沒法出行,在家休息,8月出現了疫情,在家辦公一個月,9月疫情過去,終於能來公司上班了。博客也荒廢了一段時間,接下來,我會陸續更新一些vue相關的文章,跟一家一起努力進步

Vue (讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架。
特點: 易用,靈活,高效 漸進式框架

可以隨意組合需要用到的模塊 vue + components + vue-router + vuex + vue-cli

一.Vue的概念和特性

1.什麼是庫,什麼是框架?

  • 庫是將代碼集合成一個產品,庫是我們調用庫中的方法實現自己的功能。
  • 框架則是爲解決一類問題而開發的產品,框架是我們在指定的位置編寫好代碼,框架幫我們調用。

框架與庫之間最本質區別在於控制權:you call libs, frameworks call you

Vue屬於框架

2.MVC模型 && MVVM模型

  1. M:模型(Model) :對應 data 中的數據
  2. V:視圖(View) :模板
  3. VM:視圖模型(ViewModel) : Vue 實例對象

在傳統的mvc中除了model和view以外的邏輯都放在了controller中,導致controller邏輯複雜難以維護,在mvvm中view和model沒有直接的關係,全部通過viewModel進行交互

Vue是MVVM模式

3.聲明式和命令式

  • 自己寫for循環就是命令式 (命令其按照自己的方式得到結果)
  • 聲明式就是利用數組的方法forEach (我們想要的是循環,內部幫我們去做)

二.Vue的基本使用

1.mustache語法

允許開發者聲明式地將 DOM 綁定至底層 Vue 實例的數據。在使用數據前需要先聲明

  • 編寫三元表達式
  • 獲取返回值
  • JavaScript 表達式
<div id="app">
    {{ 1+1 }}
    {{ msg == 'hello'?'yes':'no' }}
    {{ {name:1} }}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
    el:'#app',
    data:{
        msg:'hello'
    }
})
</script>

2.響應式數據變化

Vue中使用Object.defineProperty重新將對象中的屬性定義,如果是數組的話需要重寫數組原型上的方法

function notify() {
    console.log('視圖更新')
}
let data = {
    name: 'jw',
    age: 18,
    arr: [1,2,3]
}
// 重寫數組的方法
let oldProtoMehtods = Array.prototype;
let proto = Object.create(oldProtoMehtods);
['push', 'pop', 'shift', 'unshift'].forEach(method => {
    proto[method] = function (...args) {
        let inserted;
        switch (method) {
            case 'push':
            case 'unshift':
                inserted = args;
                break;
        }
        observerArray(inserted)
        notify();
        oldProtoMehtods[method].call(this, ...args)
    }
})
function observerArray(obj) { // 觀察數組中的每一項
    for (let i = 0; i < obj.length; i++) {
        observer(obj[i]);
    }
}
function observer(obj) {
    if(typeof obj !== 'object'){
        return obj
    }
    if (Array.isArray(obj)) {
        obj.__proto__ = proto
        observerArray(obj);
    }else{
        for (let key in obj) {
            defineReactive(obj, key, obj[key]);
        }
    }
}
function defineReactive(obj, key, value) {
    observer(value); // 再一次循環value
    Object.defineProperty(obj, key, { // 不支持數組
        get() {
            return value;
        },
        set(val) {
            notify();
            observer(val);
            value = val;
        }
    });
}
observer(data);
data.arr.push({name:'jw'})
console.log(data.arr);

缺陷

  • 不能通過通過長度,索引改變數組
  • 不能給對象新增屬性
  • 需要通過vm.$setvm.$delete方法強制添加/刪除響應式數據

特點: 使用對象的時候 必須先聲明屬性 ,這個屬性纔是響應式的

  • 增加不存在的屬性 不能更新視圖 (vm.$set)
  • 默認會遞歸增加 getter和setter
  • 數組裏套對象 對象是支持響應式變化的,如果是常量則沒有效果
  • 修改數組索引和長度 是不會導致視圖更新的
  • 如果新增的數據 vue中也會幫你監控(對象類型)

3.Vue實例上的方法

  • vm.$el;
  • vm.$data;
  • vm.$options;
  • vm.$nextTick();
  • vm.$mount();
  • vm.$watch();
  • vm.$set();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">{{name}} {{age.age}}</div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el:'#app',
            data(){
                return {name:'zf',age:{}}
            }
        });
        // 1) vue有個特點 不會在本輪代碼執行的時候 去重新渲染dom
        // 2) 下一個事件環中執行 (promie.then mutationobserver setimmediate settimeout)

        // 這裏會等待數據更新後重新調用回調函數
        // 視圖是異步更新的
        vm.$watch("name",function (newValue,oldValue) {
         console.log(newValue,'後');
        });

        // vm.name = 'jw';
        // vm.name = 'zf1';
        // 數據更新後會有一個隊列 將watch的callback放到隊列中,會將nextTick往後疊加
        vm.$nextTick(()=>{
            console.log(vm.$el.innerHTML); // 渲染後的真實dom
        });
        console.log('vm的數據',vm.$data); // 代表 當前實例的數據
        console.log('vm中的options',vm.$options);

        // vm.$set vm.$delete 幫我更新屬性的 
        // 新增的屬性不會導致視圖更新 ,更改數組索引也不會更新 
        // vm.age.age = 100;
        vm.$set(vm.age,'age',100); // Object.defineProperty
        // vm.$set([1,2,3],'0',100);

        // vm.$el
        // vm.$options
        // vm.$watch
        // vm.$nextTick
        // vm.$set
    </script>
</body>
</html>

三.Vue中的指令

在vue中 指令 (Directives) 是帶有 v- 前綴的特殊特性,主要的功能就是操作DOM

1.v-once

<div v-once>{{state.count}} </div>

2.v-html

永遠不要對用戶輸入使用v-html,可能會導致xss攻擊

<div v-html="text"></div>

3.v-bind

動態綁定屬性需要使用v-bind進行綁定

<img v-bind:src="src">

可以使用:來簡寫 v-bind

4.v-for

<template v-for="(fruit,index) in fruits" >
    <li :key="`item_${index}`">{{fruit}}</li>
    <li :key="`fruit_${index}`">{{fruit}}</li>
</template>

多個元素循環時外層需要增加template標籤,需要給真實元素增加key,而且key不能重複,儘量不要採用索引作爲key的值

舉個key值的例子:

5.v-if/v-else/v-show

v-if可以切換DOM元素是否存在,並且v-iffalse時內部指令不會被執行
v-show可以控制元素的顯示及隱藏,主要控制的是元素樣式

6.v-on

  • 事件的綁定 v-on綁定事件
  • 事件修飾符 (.stop .prevent) .capture .self .once .passive

7.v-model

雙向數據綁定

<input type="text" :value="value" @input="input">
<input type="text" v-model="value">
  • select
<select v-model="select">
    <option 
        v-for="fruit in fruits"
        :value="fruit">
            {{fruit}}
    </option>
</select>
  • radio
 <input type="radio" v-model="value"  value="男">
 <input type="radio" v-model="value"  value="女">
  • checkbox
<input type="checkbox" v-model="checks" value="游泳" >
<input type="checkbox" v-model="checks" value="健身">
  • 修飾符應用 .number .lazy .trim
<input type="text" v-model.number="value">
<input type="text" v-model.trim="value">
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- {{}} 小鬍子語法 取值 能運算(算出來得有返回結果) 做三元表達式 -->
        {{name}}
        {{1+1}}
        {{[1,2,3]}}
        {{true?'是':null}}
        <!-- 取對象  必須空格隔開 -->
        {{ {name:'123'} }}
        <span v-once>一次 {{name}}</span>
        <!-- 不要將用戶輸入的內容顯示到頁面上 xss攻擊 -->
        <!-- 後端返回的數據 可以通過v-html來格式化 -->
        <span v-html="tmp"></span>
        <!-- 動態綁定 -->
        <div v-bind:title="name">你好</div>
        <!-- 綁定的是一個變量屬性 -->
        <div :title="name">你好</div>

        <!-- v-for 循環數據 數組 對象 數字 (字符串) -->
        <!-- 要循環誰 就將 v-for 寫到誰的身上 -->

        <!-- vue的中的key 有什麼作用 區分元素,如果我有個按鈕做反序 -->
        <!-- 只是靜態 展示可以使用這個索引  使用唯一的key 來區分元素-->
        <!-- 每次循環時候可以自己拼接一些內容保證唯一性 -->
        不渲染
        <div v-if="false">
            <template v-for="(fruit,index) in arr" >
                <li :key="`name_${index}`">
                    {{fruit.name}}
                </li>
                <li :key="`color_${index}`">
                    {{fruit.color}}
                </li>
            </template>
        </div>
        <!-- v-if (操作dom是否顯示))  v-show(顯示隱藏 style) -->
        <!-- 指令的功能是封裝dom 操作的 --> 
        <!-- v-for 和 v-if 不要一起用 -->
        <!-- v-show 不能和template一起用 -->

        <!-- vue默認會採用複用的策略 會複用代碼 -->
        <template v-if="isShow">
            <span>你好</span>
            <input type="text" key="1">
        </template>
        <template v-else>
            <span>不好</span>
            <input type="text" key="2">
        </template>

        <!-- 雙向綁定 只要能改的 組件也可以雙向綁定 -->
        <br>
        <!-- 如何綁定方法 v-on是@的全拼-->
        <!-- $event指代的是事件源 -->
        <input type="text" :value="value" @input="fn($event)">
        <!-- 很長 -->
        <input type="text" :value="value" @input="e=>value=e.target.value">

        <!-- v-model 他就是上面的簡寫 語法糖 -->
        <input type="text" v-model="value">
        {{value}}
    </div>
    <!-- 
        v-once
        v-html
        v-bind
        v-for
        v-if / else show
        v-model 雙向綁定
     -->
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            methods:{// 就是把所有的方法的this 都變成vm,bind了 多次bind 不會生效
                fn(e){ // this指代的都是window
                     this.value = e.target.value
                }
            },
            data() {
                return {
                    value:'你好',
                    isShow:true,
                    tmp:'<h1>我很帥</h1>',
                    name: 'zf',
                    arr:[{name:'橘子',color:'綠色'},{name:'香蕉',color:' 黃色'}]
                }
            }
        });
    </script>
</body>
</html>

四.自定義指令

  • 全局指令和局部指令
  • 編寫一個自定義指令
    • 鉤子函數bind,inserted,update
    <input type="text" v-focus.color="'red'">
    Vue.directive('focus',{
        inserted:(el,bindings)=>{
            let color = bindings.modifiers.color;
            if(color){
                el.style.boxShadow = `1px 1px 2px ${bindings.value}`
            }   
            el.focus();
        }
    });
  • clickoutside指令
    <div v-click-outside="change">
        <input type="text"  @focus="flag=true" >
        <div v-show="flag">
            contenter
        </div>
    </div>
    <script>
        let vm = new Vue({
            el:'#app',
            data:{
                flag:false
            },
            methods:{
                change(){
                    this.flag = false
                }
            },
            directives:{
                'click-outside'(el,bindings,vnode){
                    document.addEventListener('click',(e)=>{
                        if(!el.contains(e.target,vnode)){
                            let eventName = bindings.expression;
                            vnode.context[eventName]()
                        }
                    })
                }
            }
        })
    </script>

五.Vue中的生命週期

  • beforeCreate 在實例初始化之後,數據觀測(data observer) 和 event/watcher 事件配置之前被調用。
  • created 實例已經創建完成之後被調用。在這一步,實例已完成以下的配置:數據觀測(data observer),屬性和方法的運算, watch/event 事件回調。這裏沒有$el
  • beforeMount 在掛載開始之前被調用:相關的 render 函數首次被調用。
  • mounted el 被新創建的 vm.$el 替換,並掛載到實例上去之後調用該鉤子。
  • beforeUpdate 數據更新時調用,發生在虛擬 DOM 重新渲染和打補丁之前。
  • updated 由於數據更改導致的虛擬 DOM 重新渲染和打補丁,在這之後會調用該鉤子。
  • beforeDestroy 實例銷燬之前調用。在這一步,實例仍然完全可用。
  • destroyed Vue 實例銷燬後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬。 該鉤子在服務器端渲染期間不被調用。

鉤子函數中該做的事情

  • created 實例已經創建完成,因爲它是最早觸發的原因可以進行一些數據,資源的請求。
  • mounted 實例已經掛載完成,可以進行一些DOM操作
  • beforeUpdate 可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
  • updated 可以執行依賴於 DOM 的操作。然而在大多數情況下,你應該避免在此期間更改狀態,因爲這可能會導致更新無限循環。 該鉤子在服務器端渲染期間不被調用。
  • destroyed 可以執行一些優化操作,清空定時器,解除綁定事件
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章