前端MVC Vue2學習總結(二)——Vue的實例、生命週期與Vue腳手架(vue-cli)

1、Vue的實例

1.一、建立一個 Vue 的實例

每一個 Vue 應用都是經過 Vue 函數建立一個新的 Vue 實例開始的:javascript

var vm = new Vue({
// 選項
})

雖然沒有徹底遵循 MVVM 模型,Vue 的設計無疑受到了它的啓發。所以在文檔中常常會使用 vm (ViewModel 的簡稱) 這個變量名錶示 Vue 實例。css

一、vue.js就是一個構造器,經過構造器Vue來實例化一個對象;例如:var vm = new Vue({});
二、實例化Vue時,須要傳入一個參數(選項對象);
三、參數:選項對象能夠包含,數據(data)、掛載元素(el)、方法(methods)、模版(template)、生命週期函數等等;
四、擴展構造器Vue,從而用預約義選項建立可複用的組件構造器,全部組件都是被擴展的Vue的實例,使用Vue.extend({})來擴展;
注意:儘管能夠命令式地建立擴展實例,不過在多數狀況下建議將組件構造器註冊爲一個自定義元素,而後聲明式地用在模板中。html

當建立一個 Vue 實例時,你能夠傳入一個選項對象。這篇教程主要描述的就是如何使用這些選項來建立你想要的行爲。做爲參考,你也能夠在 API 文檔 中瀏覽完整的選項列表。
一個 Vue 應用由一個經過 new Vue 建立的根 Vue 實例,以及可選的嵌套的、可複用的組件樹組成。舉個例子,一個 todo 應用的組件樹能夠是這樣的:前端

Root Instance
└─ TodoList
├─ TodoItem
│ ├─ DeleteTodoButton
│ └─ EditTodoButton
└─ TodoListFooter
├─ ClearTodosButton
└─ TodoListStatistics

咱們會在稍後的組件系統章節具體展開。不過如今,你只須要明白全部的 Vue 組件都是 Vue 實例,而且接受相同的選項對象便可 (一些根實例特有的選項除外)。vue

1.二、數據與方法

當一個 Vue 實例被建立時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的全部的屬性。當這些屬性的值發生改變時,視圖將會產生「響應」,即匹配更新爲新的值。java

// 咱們的數據對象
var data = { a: 1 }

// 該對象被加入到一個 Vue 實例中
var vm = new Vue({
  data: data
})

// 他們引用相同的對象!
vm.a === data.a // => true

// 設置屬性也會影響到原始數據
vm.a = 2
data.a // => 2

// ... 反之亦然
data.a = 3
vm.a // => 3

當這些數據改變時,視圖會進行重渲染。值得注意的是只有當實例被建立時 data 中存在的屬性是響應式的。也就是說若是你添加一個新的屬性,像:node

vm.b = 'hi'

那麼對 b 的改動將不會觸發任何視圖的更新。jquery

示例:webpack

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>vue2實例</title>
    </head>

    <body>
        <div id="app1">
            <input type="text" v-model="a"/>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var data={a:1}
            //實例
            var vm = new Vue({
                el: "#app1",
                data:data,
                updated:function(){
                    console.log("實例被更新了!");
                }
            });
        </script>
    </body>

</html>

結果:git

若是你知道你會在晚些時候須要一個屬性,可是一開始它爲空或不存在,那麼你僅須要設置一些初始值。好比:

data: {
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: [],
error: null
}

除了 data 屬性,Vue 實例暴露了一些有用的實例屬性與方法。它們都有前綴 $,以便與用戶定義的屬性區分開來。例如:

var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})

vm.$data === data // => true
vm.$el === document.getElementById('example') // => true

// $watch 是一個實例方法
vm.$watch('a', function (newValue, oldValue) {
// 這個回調將在 `vm.a` 改變後調用
})

在將來,你能夠在 API 參考查閱到完整的實例屬性和方法的列表

1.三、實例屬性

解釋

vm._uid // 自增的id
vm._isVue // 標示是vue對象,避免被observe
vm._renderProxy // Proxy代理對象
vm._self // 當前vm實例

vm.$parent // 用於自定義子組件中,指向父組件的實例
vm.$root // 指向根vm實例
vm.$children // 當前組件的子組件實例數組
vm.$refs 

vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false // 標識是否已掛載
vm._isDestroyed = false // 標識是否已銷燬
vm._isBeingDestroyed = false // 標識是否正在銷燬

vm._events // 當前元素上綁定的自定義事件
vm._hasHookEvent // 標示是否有hook:開頭的事件

vm.$vnode // 當前自定義組件在父組件中的vnode,等同於vm.$options._parentVnode
vm._vnode // 當前組件的vnode
vm._staticTrees // 當前組件模板內分析出的靜態內容的render函數數組
vm.$el // 當前組件對應的根元素

vm.$slots // 定義在父組件中的slots,是個對象鍵爲name,值爲響應的數組
vm.$scopedSlots = emptyObject
// 內部render函數使用的建立vnode的方法
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
// 用戶自定義render方法時,傳入的參數
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

vm._props // 被observe的存儲props數據的對象
vm._data // 被observe的存儲data數據的對象
vm._computedWatchers // 保存計算屬性建立的watcher對象

1.四、實例方法

1.五、實例參數vm.$options

vm.$options其實也就是咱們new Vue(options)options這個選項對象可傳入的屬性

declare type ComponentOptions = {
  // data
  data: Object | Function | void;  // 傳入的data數據
  props?: { [key: string]: PropOptions }; // props傳入的數據
  propsData?: ?Object;  // 對於自定義組件,父級經過`props`傳過來的數據
  computed?: {  // 傳入的計算屬性
    [key: string]: Function | {
      get?: Function;
      set?: Function;
      cache?: boolean
    }
  };
  methods?: { [key: string]: Function }; // 傳入的方法
  watch?: { [key: string]: Function | string };  // 傳入的watch

  // DOM
  el?: string | Element;  // 傳入的el字符串
  template?: string;  // 傳入的模板字符串
  render: (h: () => VNode) => VNode;  // 傳入的render函數
  renderError?: (h: () => VNode, err: Error) => VNode;
  staticRenderFns?: Array<() => VNode>;

  // 鉤子函數
  beforeCreate?: Function;
  created?: Function;
  beforeMount?: Function;
  mounted?: Function;
  beforeUpdate?: Function;
  updated?: Function;
  activated?: Function;
  deactivated?: Function;
  beforeDestroy?: Function;
  destroyed?: Function;

  // assets
  directives?: { [key: string]: Object }; // 指令
  components?: { [key: string]: Class<Component> }; // 子組件的定義
  transitions?: { [key: string]: Object };
  filters?: { [key: string]: Function }; // 過濾器

  // context
  provide?: { [key: string | Symbol]: any } | () => { [key: string | Symbol]: any };
  inject?: { [key: string]: string | Symbol } | Array<string>;

  // component v-model customization
  model?: {
    prop?: string;
    event?: string;
  };

  // misc
  parent?: Component; // 父組件實例
  mixins?: Array<Object>; // mixins傳入的數據
  name?: string; // 當前的組件名
  extends?: Class<Component> | Object; // extends傳入的數據
  delimiters?: [string, string]; // 模板分隔符

  // 私有屬性,均爲內部建立自定義組件的對象時使用
  _isComponent?: true;  // 是不是組件
  _propKeys?: Array<string>; // props傳入對象的鍵數組
  _parentVnode?: VNode; // 當前組件,在父組件中的VNode對象
  _parentListeners?: ?Object; // 當前組件,在父組件上綁定的事件
  _renderChildren?: ?Array<VNode>; // 父組件中定義在當前元素內的子元素的VNode數組(slot)
  _componentTag: ?string;  // 自定義標籤名
  _scopeId: ?string;
  _base: Class<Component>; // Vue
  _parentElm: ?Node; // 當前自定義組件的父級dom結點
  _refElm: ?Node; // 當前元素的nextSlibing元素,即當前dom要插入到_parentElm結點下的_refElm前
}

1.5.一、computed計算屬性

在模板中綁定表達式是很是便利的,可是它們實際上只用於簡單的操做。在模板中放入太多的邏輯會讓模板太重且難以維護。例如: 

<span>{{msg.split('').reverse().join('')}}</span>

使用計算屬性定義成一個方法能夠複用且模板會更加簡潔:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>vue2實例</title>
    </head>

    <body>
        <div id="app1">
            <p>
                <input type="text" v-model="msg" />
                <span>{{msg.split('').reverse().join('')}}</span>
            </p>
            <p>
                <input type="text" v-model="msg" />
                <span>{{revMsg}}</span>
            </p>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    msg: "hello"
                },
                computed: {
                    revMsg: function() {
                        return this.msg.split('').reverse().join('');
                    }
                }
            });
        </script>
    </body>

</html>

結果:

注意:

一、computed中定義的方法只容許當着屬性用,不能帶參數,這限制它的複用性。

二、當方法中的屬性發生變化時方法將從新調用

三、不該該使用箭頭函數來定義計算屬性函數 

四、 computed計算屬性能夠對屬性進行緩存的,計算屬性只有當該屬性發生變化的時候纔會從新計算值

五、若是一個屬性不能完成須要的功能時能夠考慮轉成計算

1.5.二、watch計算屬性

一個對象,鍵是須要觀察的表達式,值是對應回調函數。值也能夠是方法名,或者包含選項的對象。Vue 實例將會在實例化時調用 $watch(),遍歷 watch 對象的每個屬性。

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>vue2實例</title>
    </head>

    <body>
        <div id="app1">
            <p>
                a:
                <input type="text" v-model="a" />{{a}}<br/> b:
                <input type="text" v-model="b" />{{b}}<br/> c:
                <input type="text" v-model="c.x.y.z" />{{c.x.y.z}}<br/> d:
                <input type="text" v-model="d" />{{d}}<br/>
            </p>
            <p>
                n:<input type="text" v-model="c.x.y.n" />{{c.x.y.n}}
            </p>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    a: 1,
                    b: 2,
                    c: {
                        x: {
                            y: {
                                z: 3,
                                n: 3
                            }
                        }
                    },
                    d: 4
                },
                watch: {
                    a: function(val, oldVal) {
                        console.log('a新: %5s, 原: %5s', val, oldVal);
                    },
                    // 方法名
                    b: 'watchb',
                    //對象,深度監視
                    c: {
                        handler: function(val, oldVal) {
                            console.log('c新: %5s, 原: %5s', JSON.stringify(val),JSON.stringify(oldVal));
                        },
                        deep:true
                    },
                    //當即監視
                    d: {
                        handler: function(val, oldVal) {
                            console.log('c新: %5s, 原: %5s', val,oldVal);
                        },
                        immediate:true  //設置初始值時也將調用
                    }
                },
                methods: {
                    watchb: function(val, oldVal) {
                        console.log('b新: %5s, 原: %5s',  val, oldVal);
                    }
                }
            });

            var watchb = function(val, oldVal) {
                console.log('b新: %5s, 原: %5s', val, oldVal);
            }
        </script>
    </body>

</html>

結果:

注意:不該該使用箭頭函數來定義 watcher 函數、對象類型時並不是深拷貝的,只是引用。

1.5.三、方法methods

methods 將被混入到 Vue 實例中。能夠直接經過 VM 實例訪問這些方法,或者在指令表達式中使用。方法中的 this 自動綁定爲 Vue 實例。

var vm = new Vue({
  data: { a: 1 },
  methods: {
    plus: function () {
      this.a++
    }
  }
})
vm.plus()
vm.a // 2

 示例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vue2實例</title>
    </head>
    <body>
        <div id="app1">
            <button type="button" v-on:click="add(2)">{{msg}}</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data:{
                    msg:"vue"
                },
                methods:{
                    add:function(str){
                        return this.msg+=str;
                    }
                }
            });
            console.log(app1.add(3));
        </script>
    </body>

</html>

結果:

注意,不該該使用箭頭函數來定義 method 函數 (例如 plus: () => this.a++)。理由是箭頭函數綁定了父級做用域的上下文,因此 this 將不會按照指望指向 Vue 實例,this.a 將是 undefined。

1.5.四、小結

computed是計算屬性的,methods是計算方法的,最主要的區別是 computed計算屬性能夠對
屬性進行緩存的,計算屬性只有當該屬性發生變化的時候纔會從新計算值,只要值沒有改變,它是不會從新渲染的,可是methods方法不一樣,每次調用該方法的時候,都會從新執行的。

一、每一個Vue的實例都會代理其data對象裏的全部屬性,被代理的屬性是響應的;

二、若是實例建立以後添加新的屬性到實例上,不會觸發視圖更新;

三、不要在實例屬性或者回調函數中(如 vm.$watch('a', newVal => this.myMethod()))使用箭頭函數。由於箭頭函數綁定父上下文,因此 this 不會像預想的同樣是 Vue 實例,而是 this.myMethod 未被定義。

四、Vue實例暴露了一些有用的實例屬性和方法,帶有前綴 $ 便於與代理的data區分

a、vm.$el:類型(HTMLElement)掛載元素,Vue實例的DOM根元素;
b、vm.$data:類型(Object),Vue實例觀察的數據對象
c、vm.$props:類型(Object),屬性
d、vm.$options:類型(Object),用於當前Vue實例的初始化選項,在選項中須要包含自定義屬性的時候頗有用。
e、vm.$parent:類型(Vue實例),父實例。
f、vm.$root:類型(Vue實例),當前組件樹的根Vue實例,若是沒有父實例,就是實例自己。
h、vm.$children:類型(Array(Vue實例)),當前實例的直接子組件
須要注意 $children 並不保證順序,也不是響應式的。若是你發現本身正在嘗試使用 $children 來進行數據綁定,考慮使用一個數組配合 v-for 來生成子組件,而且使用 Array 做爲真正的來源。
i、vm.$slots:類型({ [name: string]: ?Array<VNode> }),用來訪問被 slot 分發的內容。每一個具名 slot 有其相應的屬性(例如:slot="foo" 中的內容將會在 vm.$slots.foo 中被找到)。default 屬性包括了全部沒有被包含在具名 slot 中的節點。
k、vm.$refs:類型(Object),一個對象,其中包含了全部擁有 ref 註冊的子組件;
l、vm.$isServer:類型(boolean),當前Vue實例是否運行於服務器;

官網對應

1.5.五、箭頭函數

箭頭函數是ES6引入的一種語法糖,使得寫函數更加簡便,相似Lambda表達式,基本格式以下:

()=>{}

示例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vue2實例</title>
    </head>
    <body>
        <div id="app1">
        </div>
        <script type="text/javascript">
            var m1=a=>a+1;
            console.log(m1(100));
            //相似
            var m2=function(a){
                return a+1;
            }
            console.log(m2(100));
            
            var m3=(a,b)=>a+b;
            console.log(m3(100,200));
            
            var m4=(a,b)=>{a++; b++; return a+b;};  //若是方法體中有多個表達式,則須要大括號與return
            console.log(m4(100,200));
        </script>
    </body>

</html>

結果:

2、生命週期

2.一、實例生命週期

每一個 Vue 實例在被建立以前都要通過一系列的初始化過程。例如須要設置數據監聽、編譯模板、掛載實例到 DOM、在數據變化時更新 DOM 等。同時在這個過程當中也會運行一些叫作生命週期鉤子的函數,給予用戶機會在一些特定的場景下添加他們本身的代碼。
好比 created 鉤子能夠用來在一個實例被建立以後執行代碼:

new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 實例
console.log('a is: ' + this.a)
}
})
// => "a is: 1"


也有一些其它的鉤子,在實例生命週期的不一樣場景下調用,如 mounted、updated、destroyed。鉤子的 this 指向調用它的 Vue 實例。
不要在選項屬性或回調上使用箭頭函數,好比 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。由於箭頭函數是和父級上下文綁定在一塊兒的,this 不會是如你所預期的 Vue 實例,常常致使 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之類的錯誤。

2.二、生命週期圖示

下圖說明了實例的生命週期。你不須要立馬弄明白全部的東西,不過隨着你的不斷學習和使用,它的參考價值會愈來愈高。

中文版:

 

1. beforeCreate

在實例初始化以後,數據觀測(data observer) 和 event/watcher 事件配置以前被調用。

2. created

實例已經建立完成以後被調用。在這一步,實例已完成如下的配置:數據觀測(data observer),屬性和方法的運算, watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。 能夠在組件的這個期間請求數據,若是是keep-alive組件會被緩存起來,生命週期不會再次觸發,若是須要更新數據能夠watch當前router變化,若是router是當前組件所在的router則請求數據。

methods : {
getData : function(id){
...
this.content = 'test';
}
},
created : function(){
this.getData(this.id);
}
...
watch : {
$route : function(){
if(this.$route.name == 'xxx'){
this.getData(this.id);
}
}
}

3. beforeMount

在掛載開始以前被調用:相關的 render 函數首次被調用。

4. mounted

vm.$el已掛載在文檔內,對已有dom節點的操做能夠在這期間進行。

5. beforeUpdate

數據更新時調用,發生在虛擬 DOM 從新渲染和打補丁以前。

能夠在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。

6.updated

因爲數據更改致使的虛擬 DOM 從新渲染和打補丁,在這以後會調用該鉤子。

當這個鉤子被調用時,組件 DOM 已經更新,因此你如今能夠執行依賴於 DOM 的操做。然而在大多數狀況下,你應該避免在此期間更改狀態,由於這可能會致使更新無限循環。

7.activated

keep-alive 組件激活時調用。

8.deactivated

keep-alive 組件停用時調用。

9.beforeDestroy

實例銷燬以前調用。在這一步,實例仍然徹底可用。

10.destroyed

Vue 實例銷燬後調用。調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。

2.2.0、控制檯輸出技巧

console.log支持的格式標誌有:

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    var tom={name:"tom",age:10};
    console.group("開始");
    console.group("第一組");
    console.log("%c%s%o","background:red;color:yellow;",'對象是:',tom);
    console.groupEnd();

    console.group("第二組");
    console.log("%c%s%o","background:red;color:yellow;",'對象是:',tom);
    console.groupEnd();

    console.group("第三組");
    console.log("%c%s%o","background:red;color:yellow;",'對象是:',tom);
    console.groupEnd();
    console.groupEnd();
</script>
</body>
</html>

結果:

2.三、生命週期示例一

示例1:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>vue2生命週期</title>
    </head>
    <body>
        <div id="app1">
            <input v-model="msg" /> {{msg}}
        </div>
        <button type="button" onclick="destroy()">銷燬</button>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            //格式化輸出
            console.log("示例:%c%s","background:red;color:#fff","vue2生命週期","開始了");
            
            var app1 = new Vue({
                el: "#app1",
                data:{
                    msg:"vue"
                },
                beforeCreate:function(){
                    console.log("建立前:"+this.msg);
                },
                created:function(){
                    console.log("建立後:"+this.msg+","+this.$el);
                },
                beforeMount:function(){
                    console.log("掛載前:");
                    console.log(this.$el);
                },
                mounted:function(){
                    console.log("掛載後:");
                    console.log(this.$el);
                },
                beforeUpdate:function(){
                    console.log("實例更新前:");
                    console.log(this.msg);
                    console.log(this.$el);
                },
                updated:function(){
                    console.log("實例更新後:");
                    console.log(this.msg);
                    console.log(this.$el);
                },
                beforeDestroy:function(){
                    console.log("實例銷燬前:");
                    console.log(this.msg);                                        
                },
                destroyed:function(){
                    console.log("實例銷燬後:");
                    console.log(this.msg);
                }
            });
            
            function destroy(){
                app1.$destroy();
            }
        </script>
    </body>

</html>

初始化結果1:

修改msg的值爲vue2後的結果:

執行銷燬:

2.四、生命週期示例二

示例2:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Vue2 Demo</title>
</head>
<body>
<div id="app01">
    <h2>{{name}}</h2>
    <button @click="changename">修改name</button>
    <button @click="over">銷燬實例</button>
</div>
<script src="../../js/vue/vue.min.js"></script>
<script>
    var vm = new Vue({
        data: {
            name: 'zhangguo',
            bar:"test"
        },
        el: "#app01",
        methods: {
            changename: function () {
                this.name += ',Hello';
            },
            over:function () {
                //銷燬實例
                this.$destroy();
            }
        },
        beforeCreate: function () {
            console.group('一、beforeCreate 建立前狀態===============》');
            console.log("%c%s", "color:red", "el     : " + this.$el); //undefined
            console.log("%c%o", "color:red", "data   : " + this.$data); //undefined
            console.log("%c%s", "color:red", "name: " + this.name); //undefined
            console.groupEnd()
        },
        created: function () {
            console.group('二、created 建立後狀態===============》');
            console.log("%c%s", "color:red", "el     : " + this.$el);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        },
        beforeMount: function () {
            console.group('三、beforeMount 掛載前===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        },
        mounted: function () {
            console.group('四、mounted 掛載後===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        },
        beforeUpdate: function () {
            console.group('五、beforeUpdate 視圖更新前===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el.innerHTML);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        },
        updated: function () {
            console.group('六、updated 視圖更新後===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el.innerHTML);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        },
        beforeDestroy: function () {
            console.group('七、beforeDestroy 實例銷燬前===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el.innerHTML);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        }
        ,
        destroyed: function () {
            console.group('八、beforeDestroy 實例銷燬後===============》');
            console.log("%c%s", "color:red", "el     : ", this.$el.innerHTML);
            console.log("%c%s", "color:red", "data   : " + JSON.stringify(this.$data));
            console.log("%c%s", "color:red", "name: " + this.name);
            console.groupEnd()
        }
    });
</script>
</body>
</html>

 

初始化結果:

更新name的值:

銷燬實例

2.五、手動掛載與調用事件

2.5.一、手動掛載

vm.$mount( [elementOrSelector] ) 若是 Vue 實例在實例化時沒有收到 el 選項,則它處於「未掛載」狀態,沒有關聯的 DOM 元素。可使用 vm.$mount() 手動地掛載一個未掛載的實例。

若是沒有提供 elementOrSelector 參數,模板將被渲染爲文檔以外的的元素,而且你必須使用原生 DOM API 把它插入文檔中。
這個方法返回實例自身,於是能夠鏈式調用其它實例方法。

var MyComponent = Vue.extend({
template: '<div>Hello!</div>'
})

// 建立並掛載到 #app (會替換 #app)
new MyComponent().$mount('#app')

// 同上
new MyComponent({ el: '#app' })

// 或者,在文檔以外渲染而且隨後掛載
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

示例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Vue2 Demo</title>
</head>
<body>
<div id="app01">
</div>
<button type="button" onclick="mount01()">手動掛載方法1</button>
<button type="button" onclick="mount02()">手動掛載方法2</button>
<button type="button" onclick="mount03()">手動掛載方法3</button>
<script src="../../js/vue/vue.min.js"></script>
<script>
    var vm = new Vue({
        data: {
            name: 'zhangguo'
        },
        template:'<h2>{{name}}</h2>'
    });

    function mount01() {
        //方法1
        //手動掛載到指定DOM
        vm.$mount("#app01");
    }

    function mount02() {
        //方法1
        //手動掛載,觸發編譯
        vm.$mount();
        //將編譯生成的內容元素添加到要掛載的DOM中,做爲子元素
        document.getElementById("app01").appendChild(vm.$el);
    }

    function mount03() {
        //擴展出一個新的Vue構造器
        var Component01=Vue.extend({
            template:"<h2>{{name}}</h2>"
        });

        var c01=new Component01({
            data: {
                name: 'zhangguo'
            },
            el:"#app01"
        });
    }

</script>
</body>
</html>

運行結果:

2.5.二、銷燬實例

vm.$destroy() 徹底銷燬一個實例。清理它與其它實例的鏈接,解綁它的所有指令及事件監聽器。

2.5.三、強制更新

vm.$forceUpdate() 迫使 Vue 實例從新渲染。注意它僅僅影響實例自己和插入插槽內容的子組件,而不是全部子組件。

3、Vue腳手架(vue-cli)

單頁Web應用(single page web application,SPA),就是隻有一張Web頁面的應用,是加載單個HTML 頁面並在用戶與應用程序交互時動態更新該頁面的Web應用程序。

提供一個官方命令行工具,可用於快速搭建大型單頁應用(SPA)。該工具爲現代化的前端開發工做流提供了開箱即用的構建配置。只需幾分鐘便可建立並啓動一個帶熱重載、保存時靜態檢查以及可用於生產環境的構建配置的項目:

# 全局安裝 vue-cli
$ npm install --global vue-cli
# 建立一個基於 webpack 模板的新項目
$ vue init webpack my-project
# 安裝依賴,走你
$ cd my-project
$ npm install
$ npm run dev

注意:CLI 工具假定用戶對 Node.js 和相關構建工具備必定程度的瞭解。若是你是新手,咱們強烈建議先在不用構建工具的狀況下通讀指南,在熟悉 Vue 自己以後再使用 CLI。

3.一、環境搭建

3.1.一、安裝node.js

從node.js官網下載並安裝node,安裝過程很簡單,一路「下一步」就能夠了。安裝完成以後,打開命令行工具(win+r,而後輸入cmd),輸入 node -v,以下圖,若是出現相應的版本號,則說明安裝成功。

若是安裝不成功,能夠直接把安裝包修改爲壓縮包,解壓後配置環境變量也能夠,就成了綠色版。

 

這裏須要說明下,由於在官網下載安裝node.js後,就已經自帶npm(包管理工具)了,另須要注意的是npm的版本最好是3.x.x以上,以避免對後續產生影響。

注意版本不能過低,若是您已經安裝了低版本的node可使用npm直接更新。

3.1.二、修改npm爲淘寶鏡像

由於npm的倉庫有許多在國外,訪問的速度較慢,建議修改爲cnpm,換成taobao的鏡像。

打開命令行工具,複製以下配置:

npm install -g cnpm --registry=https://registry.npm.taobao.org

安裝這裏是由於咱們用的npm的服務器是外國,有的時候咱們安裝「依賴」的時候很很慢很慢超級慢,因此就用這個cnpm來安裝咱們說須要的「依賴」。安裝完成以後輸入 cnpm -v,以下圖,若是出現相應的版本號,則說明安裝成功。

版本號:

3.1.三、安裝webpack

安裝webpack,打開命令行工具輸入:

npm install webpack -g

安裝完成以後輸入

webpack -v

以下圖,若是出現相應的版本號,則說明安裝成功。

3.1.四、安裝vue-cli腳手架構建工具

打開命令行工具輸入:

cnpm install vue-cli -g

安裝完成以後輸入 vue -V(注意這裏是大寫的「V」),以下圖,若是出現相應的版本號,則說明安裝成功。

3.二、構建項目

1)、在硬盤上找一個文件夾放工程用的。這裏有兩種方式指定到相關目錄:

①cd 目錄路徑

②若是以安裝git的,在相關目錄右鍵選擇Git Bash Here

2)、安裝vue腳手架輸入:vue init webpack projectName,注意這裏的「projectName」 是項目的名稱能夠說是隨便的起名,可是「不能用中文」。

提示選擇項:

$ vue init webpack exprice --------------------- 這個是那個安裝vue腳手架的命令
This will install Vue 2.x version of the template. ---------------------這裏說明將要建立一個vue 2.x版本的項目
For Vue 1.x use: vue init webpack#1.0 exprice
? Project name (exprice) ---------------------項目名稱
? Project name exprice
? Project description (A Vue.js project) ---------------------項目描述
? Project description A Vue.js project
? Author Datura --------------------- 項目建立者
? Author Datura
? Vue build (Use arrow keys)
? Vue build standalone
? Install vue-router? (Y/n) --------------------- 是否安裝Vue路由,也就是之後是spa(但頁面應用須要的模塊)
? Install vue-router? Yes
? Use ESLint to lint your code? (Y/n) n ---------------------是否啓用eslint檢測規則,這裏我的建議選no
? Use ESLint to lint your code? No
? Setup unit tests with Karma + Mocha? (Y/n)
? Setup unit tests with Karma + Mocha? Yes
? Setup e2e tests with Nightwatch? (Y/n)
? Setup e2e tests with Nightwatch? Yes
vue-cli · Generated "exprice".
To get started: --------------------- 這裏說明如何啓動這個服務
cd exprice
npm install
npm run dev
View Code

3)、cd 命令進入建立的工程目錄,首先cd projectName;

4)、安裝項目依賴:npm install,由於自動構建過程當中已存在package.json文件,因此這裏直接安裝依賴就行。不要從國內鏡像cnpm安裝(會致使後面缺了不少依賴庫),可是可是若是真的安裝「個把」小時也沒成功那就用:cnpm install 吧

5)、安裝 vue 路由模塊 vue-router 和網絡請求模塊 vue-resource,輸入:cnpm install vue-router vue-resource --save。

目錄:

|-- build                            // 項目構建(webpack)相關代碼
|   |-- build.js                     // 生產環境構建代碼
|   |-- check-version.js             // 檢查node、npm等版本
|   |-- dev-client.js                // 熱重載相關
|   |-- dev-server.js                // 構建本地服務器
|   |-- utils.js                     // 構建工具相關
|   |-- webpack.base.conf.js         // webpack基礎配置
|   |-- webpack.dev.conf.js          // webpack開發環境配置
|   |-- webpack.prod.conf.js         // webpack生產環境配置
|-- config                           // 項目開發環境配置
|   |-- dev.env.js                   // 開發環境變量
|   |-- index.js                     // 項目一些配置變量
|   |-- prod.env.js                  // 生產環境變量
|   |-- test.env.js                  // 測試環境變量
|-- src                              // 源碼目錄
|   |-- components                     // vue公共組件
|   |-- store                          // vuex的狀態管理
|   |-- App.vue                        // 頁面入口文件
|   |-- main.js                        // 程序入口文件,加載各類公共組件
|-- static                           // 靜態文件,好比一些圖片,json數據等
|   |-- data                           // 羣聊分析獲得的數據用於數據可視化
|-- .babelrc                         // ES6語法編譯配置
|-- .editorconfig                    // 定義代碼格式
|-- .gitignore                       // git上傳須要忽略的文件格式
|-- README.md                        // 項目說明
|-- favicon.ico 
|-- index.html                       // 入口頁面
|-- package.json                     // 項目基本信息

3.三、運行項目

6)、啓動項目,輸入:npm run dev。服務啓動成功後瀏覽器會默認打開一個「歡迎頁面」,以下圖:

編譯成功後能夠直接在瀏覽器中查看項目:

3.四、使用WebStorm IDE建立Vue-cli項目

在webstorm中新建項目,選擇vue-cli:

輸出項目名稱:

項目描述:

做者:

構建模式:

是否使用路由:

是否使用ESLint做語法檢查:

是否單元測試:

是否安裝e2e(測試):

是否使用npm做爲包管理器:

選擇安裝包:

若是網速比較慢,在上面這個界面中不要選擇用npm,手動在控制檯cnmp install

全部的包下載完成後就能夠構建 並運行了:

運行結果:

 

3.五、Vue-cli HelloWorld

瞭解了默認的模板內容,咱們能夠開始定義本身的vue程序了,這裏寫一個簡單的HelloWorld,在src目錄下建立一個Hi.vue文件,內容以下:

<template>
    <div id="app1">
        <input v-model="msg" v-on:click="sayhi"/>
        <p>
            <h2>{{msg}}</h2>
        </p>
    </div>
</template>

<script>
    export default {
        name: 'Hi',
        data() {
            return {
                msg: 'My First vue-cli app!'
            }
        },
        methods:{
            sayhi:function(){
                alert(this.msg);
            }
        }
    }
</script>

<style>
    #app1 {
        font-family: "microsoft yahei";
        color: dodgerblue;
        font-size: 20px;
    }
</style>

修改main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './Hi'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

運行結果:

3.六、Vue-cli路由與單頁

3.6.一、建立一個帶路由的項目

建立好的項目以下

3.6.二、定義組件

在src/compontents目錄下建立3個vue組件

CompontentA:

<template>
  <div>
    <h2>{{msg}}</h2>
  </div>
</template>

<script>
  export default {
    name: "ComponentA",
    data(){
      return {
        msg:"ComponentA,這是組件A!",
      }
    }
  }
</script>

<style scoped>
  h2 {
    color: crimson;
  }
</style>

ComponentB:

<template>
  <div>
    <h2>{{msg}}</h2>
  </div>
</template>

<script>
  export default {
    name: "ComponentB",
    data(){
      return {
        msg:"ComponentB,這是組件B!",
      }
    }
  }
</script>

<style scoped>
  h2 {
    color:limegreen;
  }
</style>

ComponentC:

<template>
  <div>
    <h2>{{msg}}</h2>
  </div>
</template>

<script>
  export default {
    name: "ComponentC",
    data(){
      return {
        msg:"ComponentC,這是組件C!",
      }
    }
  }
</script>

<style scoped>
  h2 {
    color:dodgerblue;
  }
</style>

結果:

3.6.三、修改路由

修改src/router目錄下的index.js文件

增長路由,一個組件對應一個訪問地址:

import Vue from 'vue'
import Router from 'vue-router'
import App from '@/App'
import A from '@/components/ComponentA'
import B from '@/components/ComponentB'
import C from '@/components/ComponentC'

Vue.use(Router);

export default new Router({
  routes: [
    {
      path: '/',
      name: 'App',
      component: App
    }, {
      path: '/a',
      name: 'ComponentA',
      component: A
    }, {
      path: '/b',
      name: 'ComponentB',
      component: B
    }, {
      path: '/c',
      name: 'ComponentC',
      component: C
    }
  ]
}) 

3.6.四、引用連接地址

修改index.html文件:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vuecli06</title>
  </head>
  <body>
    <div id="app">
      <ul>
        <li><a href="/">首頁</a> </li>
        <li><a href="#/a">組件A</a> </li>
        <li><a href="#/b">組件B</a> </li>
        <li><a href="#/c">組件C</a> </li>
      </ul>
      <!--router-view主要是構建 SPA (單頁應用) 時,方便渲染你指定路由對應的組件。你能夠 router-view 當作是一個容器,它渲染的組件是你使用 vue-router 指定的。-->
      <router-view></router-view>
    </div>
    <!-- built files will be auto injected -->
  </body>
</html>

 

router-view主要是構建 SPA (單頁應用) 時,方便渲染你指定路由對應的組件。你能夠 router-view 當作是一個容器,它渲染的組件是你使用 vue-router 指定的。

打包後運行結果:

點擊a

點擊b

點擊c

3.七、Vue-cli中依賴jQuery與BootStrap

3.7.一、添加依賴包

項目根目錄下找到package.json 添加

"bootstrap": "^3.3.6",
"jquery": "^2.1.4",

版本能夠根據本身的須要修改

cnpm install

在控制檯下安裝。

3.7.二、導入jQuery與Bootstrap

在main.js 導入 (注意導入是node_modules下的路徑能夠點進去查看具體位置)min是壓縮後文件建議導入這個

import 'jquery/dist/jquery.min.js'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js' 

3.7.三、使用內置插件ProvidePlugin自動加載模塊

此時jQuery並未依賴成功,將提示錯誤:

插件ProvidePlugin(點擊查看)自動加載模塊,而沒必要處處 import 或 require。

需在build/webpack.base.conf.js中增長插件配置

const webpack = require('webpack')

配置中添加

plugins: [
  new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery",
    "windows.jQuery": "jquery"
  })
],

完整結果:

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const webpack = require('webpack')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

const webpack = require('webpack')


module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "windows.jQuery": "jquery"
    })
  ],
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}
View Code

3.7.四、使用jQuery與Bootstrap

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vuecli06</title>
  </head>
  <body>
    <div id="app">
      <ul class="nav nav-tabs">
        <li role="presentation" class="active"><a href="/">首頁</a></li>
        <li role="presentation"><a href="#/a">組件A</a></li>
        <li role="presentation"><a href="#/b">組件B</a></li>
        <li role="presentation"><a href="#/c">組件C</a></li>
      </ul>
      <!--router-view主要是構建 SPA (單頁應用) 時,方便渲染你指定路由對應的組件。你能夠 router-view 當作是一個容器,它渲染的組件是你使用 vue-router 指定的。-->
      <router-view></router-view>
    </div>
    <!-- built files will be auto injected -->
  </body>
</html>

運行結果:

4、示例下載

https://git.coding.net/zhangguo5/vue2.git

5、視頻

https://www.bilibili.com/video/av17503637/

6、做業

一、請定義任意一個Vue實例,觸發Vue實例中的8個事件,將結果輸出到控制檯,要求能夠觀察到數據初始化與掛載狀況。

二、請使用vuecli+vue2+bootstrap完成以下功能:

要求以下:

a)、實現添加功能

b)、實現刪除功能

c)、實現編輯功能,增長按鈕

d)、實現隔行換色

e)、實現按年齡排序

參考

相關文章
相關標籤/搜索