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

大家好,我是前端嵐楓移必,一枚二線城市的程序媛,下半年對于我們來說是比較特殊的幾個月遭殉,7月底石挂,鄭州出現(xiàn)好多年不遇的水災(zāi),沒法出行险污,在家休息誊稚,8月出現(xiàn)了疫情,在家辦公一個月罗心,9月疫情過去里伯,終于能來公司上班了。博客也荒廢了一段時間渤闷,接下來疾瓮,我會陸續(xù)更新一些vue相關(guān)的文章,跟一家一起努力進步

Vue (讀音 /vju?/飒箭,類似于 view) 是一套用于構(gòu)建用戶界面的漸進式框架狼电。
特點: 易用,靈活弦蹂,高效 漸進式框架

image.png

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

一.Vue的概念和特性

1.什么是庫肩碟,什么是框架?

  • 庫是將代碼集合成一個產(chǎn)品,庫是我們調(diào)用庫中的方法實現(xiàn)自己的功能。
  • 框架則是為解決一類問題而開發(fā)的產(chǎn)品,框架是我們在指定的位置編寫好代碼凸椿,框架幫我們調(diào)用削祈。

框架與庫之間最本質(zhì)區(qū)別在于控制權(quán):you call libs, frameworks call you

Vue屬于框架

2.MVC模型 && MVVM模型

image.png
  1. M:模型(Model) :對應(yīng) data 中的數(shù)據(jù)
  2. V:視圖(View) :模板
  3. VM:視圖模型(ViewModel) : Vue 實例對象
image.png

在傳統(tǒng)的mvc中除了model和view以外的邏輯都放在了controller中,導(dǎo)致controller邏輯復(fù)雜難以維護,在mvvm中view和model沒有直接的關(guān)系脑漫,全部通過viewModel進行交互

Vue是MVVM模式

image.png

3.聲明式和命令式

  • 自己寫for循環(huán)就是命令式 (命令其按照自己的方式得到結(jié)果)
  • 聲明式就是利用數(shù)組的方法forEach (我們想要的是循環(huán)髓抑,內(nèi)部幫我們?nèi)プ?

二.Vue的基本使用

1.mustache語法

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

  • 編寫三元表達式
  • 獲取返回值
  • 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.響應(yīng)式數(shù)據(jù)變化

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

function notify() {
    console.log('視圖更新')
}
let data = {
    name: 'jw',
    age: 18,
    arr: [1,2,3]
}
// 重寫數(shù)組的方法
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) { // 觀察數(shù)組中的每一項
    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); // 再一次循環(huán)value
    Object.defineProperty(obj, key, { // 不支持數(shù)組
        get() {
            return value;
        },
        set(val) {
            notify();
            observer(val);
            value = val;
        }
    });
}
observer(data);
data.arr.push({name:'jw'})
console.log(data.arr);

缺陷

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

特點: 使用對象的時候 必須先聲明屬性 ,這個屬性才是響應(yīng)式的

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

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有個特點 不會在本輪代碼執(zhí)行的時候 去重新渲染dom
        // 2) 下一個事件環(huán)中執(zhí)行 (promie.then mutationobserver setimmediate settimeout)

        // 這里會等待數(shù)據(jù)更新后重新調(diào)用回調(diào)函數(shù)
        // 視圖是異步更新的
        vm.$watch("name",function (newValue,oldValue) {
         console.log(newValue,'后');
        });

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

        // vm.$set vm.$delete 幫我更新屬性的 
        // 新增的屬性不會導(dǎo)致視圖更新 羹饰,更改數(shù)組索引也不會更新 
        // 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,可能會導(dǎo)致xss攻擊

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

3.v-bind

動態(tài)綁定屬性需要使用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>

多個元素循環(huán)時外層需要增加template標簽,需要給真實元素增加key,而且key不能重復(fù),盡量不要采用索引作為key的值

舉個key值的例子:

image.png

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

v-if可以切換DOM元素是否存在,并且v-iffalse時內(nèi)部指令不會被執(zhí)行
v-show可以控制元素的顯示及隱藏碳却,主要控制的是元素樣式

6.v-on

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

7.v-model

雙向數(shù)據(jù)綁定

<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="健身">
  • 修飾符應(yīng)用 .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">
        <!-- {{}} 小胡子語法 取值 能運算(算出來得有返回結(jié)果) 做三元表達式 -->
        {{name}}
        {{1+1}}
        {{[1,2,3]}}
        {{true?'是':null}}
        <!-- 取對象  必須空格隔開 -->
        {{ {name:'123'} }}
        <span v-once>一次 {{name}}</span>
        <!-- 不要將用戶輸入的內(nèi)容顯示到頁面上 xss攻擊 -->
        <!-- 后端返回的數(shù)據(jù) 可以通過v-html來格式化 -->
        <span v-html="tmp"></span>
        <!-- 動態(tài)綁定 -->
        <div v-bind:title="name">你好</div>
        <!-- 綁定的是一個變量屬性 -->
        <div :title="name">你好</div>

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

        <!-- vue的中的key 有什么作用 區(qū)分元素,如果我有個按鈕做反序 -->
        <!-- 只是靜態(tài) 展示可以使用這個索引  使用唯一的key 來區(qū)分元素-->
        <!-- 每次循環(huán)時候可以自己拼接一些內(nèi)容保證唯一性 -->
        不渲染
        <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默認會采用復(fù)用的策略 會復(fù)用代碼 -->
        <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>

四.自定義指令

  • 全局指令和局部指令
  • 編寫一個自定義指令
    • 鉤子函數(shù)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 在實例初始化之后追城,數(shù)據(jù)觀測(data observer) 和 event/watcher 事件配置之前被調(diào)用刹碾。
  • created 實例已經(jīng)創(chuàng)建完成之后被調(diào)用燥撞。在這一步座柱,實例已完成以下的配置:數(shù)據(jù)觀測(data observer)迷帜,屬性和方法的運算, watch/event 事件回調(diào)色洞。這里沒有$el
  • beforeMount 在掛載開始之前被調(diào)用:相關(guān)的 render 函數(shù)首次被調(diào)用戏锹。
  • mounted el 被新創(chuàng)建的 vm.$el 替換,并掛載到實例上去之后調(diào)用該鉤子火诸。
  • beforeUpdate 數(shù)據(jù)更新時調(diào)用锦针,發(fā)生在虛擬 DOM 重新渲染和打補丁之前。
  • updated 由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補丁置蜀,在這之后會調(diào)用該鉤子奈搜。
  • beforeDestroy 實例銷毀之前調(diào)用。在這一步盯荤,實例仍然完全可用馋吗。
  • destroyed Vue 實例銷毀后調(diào)用。調(diào)用后秋秤,Vue 實例指示的所有東西都會解綁定宏粤,所有的事件監(jiān)聽器會被移除,所有的子實例也會被銷毀灼卢。 該鉤子在服務(wù)器端渲染期間不被調(diào)用绍哎。

鉤子函數(shù)中該做的事情

  • created 實例已經(jīng)創(chuàng)建完成,因為它是最早觸發(fā)的原因可以進行一些數(shù)據(jù)鞋真,資源的請求崇堰。
  • mounted 實例已經(jīng)掛載完成,可以進行一些DOM操作
  • beforeUpdate 可以在這個鉤子中進一步地更改狀態(tài)涩咖,這不會觸發(fā)附加的重渲染過程赶袄。
  • updated 可以執(zhí)行依賴于 DOM 的操作。然而在大多數(shù)情況下抠藕,你應(yīng)該避免在此期間更改狀態(tài)饿肺,因為這可能會導(dǎo)致更新無限循環(huán)。 該鉤子在服務(wù)器端渲染期間不被調(diào)用盾似。
  • destroyed 可以執(zhí)行一些優(yōu)化操作,清空定時器敬辣,解除綁定事件
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市零院,隨后出現(xiàn)的幾起案子溉跃,更是在濱河造成了極大的恐慌,老刑警劉巖告抄,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撰茎,死亡現(xiàn)場離奇詭異,居然都是意外死亡打洼,警方通過查閱死者的電腦和手機龄糊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門逆粹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人炫惩,你說我怎么就攤上這事僻弹。” “怎么了他嚷?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵蹋绽,是天一觀的道長。 經(jīng)常有香客問我筋蓖,道長卸耘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任粘咖,我火速辦了婚禮鹊奖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涂炎。我一直安慰自己忠聚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布唱捣。 她就那樣靜靜地躺著两蟀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪震缭。 梳的紋絲不亂的頭發(fā)上赂毯,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音拣宰,去河邊找鬼党涕。 笑死,一個胖子當(dāng)著我的面吹牛巡社,可吹牛的內(nèi)容都是我干的膛堤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晌该,長吁一口氣:“原來是場噩夢啊……” “哼肥荔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起朝群,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤燕耿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后姜胖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誉帅,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚜锨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片档插。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖踏志,靈堂內(nèi)的尸體忽然破棺而出阀捅,到底是詐尸還是另有隱情胀瞪,我是刑警寧澤针余,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站凄诞,受9級特大地震影響圆雁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帆谍,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一伪朽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汛蝙,春花似錦烈涮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至西土,卻和暖如春讶舰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背需了。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工跳昼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肋乍。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓鹅颊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親墓造。 傳聞我的和親對象是個殘疾皇子挪略,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容