vue.js 學習筆記

後青春期的Keats發表於2019-08-05

Vue.js

基礎

一套用於構建使用者介面的漸進式框架, 核心庫只關注檢視層,易於上手,便於與第三方庫或現有專案整合,且輕量。

宣告式渲染

使用插值表示式,基於 MVVM 來動態的影響頁面與變數

# 頁面上鍵入插值表示式
<div id="app">
  {{ message }} # View 角色
</div>
# 然後,進行 ViewModle 資料繫結。是 VM 角色
var app = new Vue({ # 新建 Vue 例項
  el: '#app', # 通過ID選擇器,來接管 div 區域
  data: { 
    message: 'Hello Vue!' # 是 Model 角色
  }
})

雙向繫結

使用 v-modle 指令實現雙向繫結

可以在一個 app 塊中繫結多個變數,在賦值的時候使用逗號隔開。這樣就漸漸的相當於 angula.js 使用 ng-app 宣告在 body上佔地為王一樣

var app = new Vue({
    el:'#app',
    data:{
        flag:true,
        user:"張三"
    }
});

並且可以在瀏覽器除錯頁,使用 app.變數名 = 值 ,替換變數的值。

條件與迴圈

條件:v-if="變數名";

當變數的值為 true 時,顯示被 v-if 指令所在標籤包裹的HTML內容。當值為 false 刪除其所在html標籤

<div id="app-3">
    <span v-if="flag">
        你能看見我嗎?
    </span>
</div>
var app3 = new Vue({
    el:'#app-3',
    data:{
        flag:true
    }
});

隱藏:v-show = "變數名";

當變數的值為 false 時,為DOM的HTML標籤新增CSS屬性: style="display: none;"

因此:對於經常需要進行顯示/隱藏切換的DOM標籤,使用 v-show 效能更加優異

迴圈:v-for="臨時變數 in 變數"

<div id="app">
    <ur v-for="user in users">
        <li>{{user.name}}---{{user.age}} </li>
    </ur>
</div>
var app = new Vue({
    el:'#app',
    data:{
        users:[
            {"name":"張三","age":23}, # JSON格式定義物件
            {"name":"李四","age":24},
            {"name":"王五","age":25},
            {"name":"趙六","age":26}
        ]
    }
});
  • 在除錯頁中可以使用 app.users.push({"name":"xxx","age":23}) 動態新增資料
  • 定義一個唯一的欄位作為 key ,可以提高遍歷效率
  • 在遍歷時以如下方式使用 index
<ur v-for="(user, index) in users":key="index">
    <li>{{index + 1}} {{user.name}}---{{user.age}}</li>
</ur>

處理使用者輸入

元件化

元件:頁面上的某一部分,當一個網頁非常大時,可以將該網頁的內容拆分成幾個部分,便於維護

定義元件

  1. 定義全域性元件
Vue.component('todo-item', { # 通過 Vue.component('元件名',{元件內容}) 定義元件
   template : "<li>Item</li>" # 通過 template 屬性定義元件的內容
});
<ul>
    <todo-item></todo-item> <!-- 在頁面以標籤的方式使用元件 -->
</ul>
  1. 定義區域性元件
// 定義區域性元件
var TodoList = {
    template : "<li>Item</li>"
};
// 註冊區域性元件
new Vue({
    el: '#app',
    components : {
        "todo-item" : TodoList # 仍然在頁面使用 todo-item 這個名字來使用元件
    })

利用元件實現 todolist

<ul>
    <!-- 在使用元件的時候,可以進行傳值,使用 : 變數名 = “值” -->
    <todo-item
            v-for="(content, index) in list"  
            :key="index" 
            :content="content" 
    ></todo-item>
</ul>
// 全域性元件
Vue.component('todo-item', {
    props : ['content'], # 用來接收傳過來的值
    template: "<li>{{content}}</li>" # 使用插值表示式來顯示值
});

元件和例項的關係

一個元件也是一個例項

​ 元件裡面也可以寫:methods / data / computed 屬性

任何Vue專案都是由 n 個例項構成的

​ 對於根例項,雖然沒有顯式的定義 template 模板屬性,但是Vue會根據 el 屬性,去找掛載點,將掛載點裡面的全部內容作為模板

元件之間的互動

父子元件之間的互動

父元件向子元件傳遞資料:

​ 使用 : 屬性名 = “值” 的方式傳遞,子元件 使用 props : ["屬性名1", "屬性名2"] 的方式接收

子元件向父元件傳遞資料:

​ 使用 : this.$emit("訊息名", 引數) 的方式來傳送訊息,在父元件的模板中使用 @訊息名 = “函式名” 的方式來接收訊息並處理。

具體的使用見練習2.

掛載點、模板、例項

掛載點: el 屬性繫結的DOM標籤。用來宣告Vue的作用域。不包含標籤內部的變數

模板: 掛載點內部的HTML內容統稱為模板。模板的定義方式有兩種:

  • 直接定義在掛載點所在的標籤體內
  • 在 Vue 例項裡使用 template 定義:
var app = new Vue({
    el:'#app',
    # 模板內容會覆蓋原本掛載點裡面的內容,請注意
    template:"<h1>Hello {{msg}}</h1>", # 定義模板時,需要用標籤來包裝內容,否則無法識別
    data:{
        msg:"Hello World"
    }
});

例項:建立的 Vue 物件

使用

安裝

Vue.js 不支援IE8及以下版本,因為他使用了IE8不支援的 ECMAScript5 的特性。

引入核心庫

<!-- 開發環境下引入完成包,生產環境引 min.js 包 -->
<script src="./vue.js"></script>

指令

以 v- 作為字首,vue指令會在渲染的DOM上應用特殊的響應行為。

v-text

繫結DOM標籤內的text文字內容。如果內容中存在HTML標籤,會被原樣展示

v-html

繫結DOM標籤內HTML內容

v-on:click = "functionName"

  • 繫結單擊事件。注意:單擊呼叫的方法只寫方法名,不寫小括號
  • 在例項中定義 methods 物件,物件內部可以定義方法
  • 另外, v-on:click 也可以簡寫成: @click
var app = new Vue({
    el:'#app',
    data:{
        text:"Hello"
    },
    methods:{ # 這個屬性用來定義例項中的方法
        changeText : function () {
            app.text = "World"
        }
    }
});
// 或者可以採用 this.text 的方式來更改 text
changeText : function () {
    this.text = "World"
}

屬性繫結

v-bind:title="title"

為 title 屬性後面的內容賦予了特殊的意義。例如此例中 “” 內的 title 表示Vue例項中的title變數的值

v-bind: 可以簡寫為 :

計算屬性

computed

用來對變數進行一些運算操作。

優點:當參與運算的變數沒有改變時,結果會採用上一次的快取值

<div id="app">
    姓:<input v-model="firstName"/>
    名:<input v-model="lastName"/>
    <div>{{fullName}}</div>
</div>

使用 computed 屬性來定義參計算結果的函式

new Vue({
    el:'#app',
    data:{
        firstName:"", # 必須提前定義為 “” 否則頁面會顯示fullName為 undefined
        lastName:""
    },
    computed:{ # 定義計算屬性
        fullName : function () {
            return this.firstName + " " + this.lastName; # 返回字串拼接結果
        }
    }
});

偵聽器

watch

監聽某個資料的變化,當它產生變化時,執行回撥函式

watch: { # 定義偵聽器
    fullName : function () { # 偵聽的變數為 fullName 
        this.count ++ ; # 回撥函式方法體
    }
}

練習1

vue1

需求:如上面的動圖,當輸入框輸入內容後,點選提交就會在下面的列表展示新新增的資料,如果使用者沒有寫任何資料點選提交,提示他應該輸入之後才能點選

<div id="app">
    <input v-model="num" ref="id"/>  <!-- 新增ref屬性,以便使用Vue選擇器來獲取該輸入框的 -->
    <button @click="add">提交</button>

    <ul>  <!-- 新增key屬性,提高遍歷速度 -->
        <li v-for="(entity, index) in list":key="index">{{entity.num}}</li>
    </ul>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data:{
            num:"",
            list:[
                {num:1},
                {num:2},
                {num:3},
                {num:4}
            ]
        },
        methods:{
            add : function () {
                if(this.num){
                    this.list.push({num:this.num});
                    this.num = ""; # 新增完成後,刪除原來的資料
                }else {
                    alert("請輸入要新增的內容後重試!");
                    this.$refs.id.focus(); # vue語法,讓輸入框獲得焦點,提高使用者體驗
                }
            }
        }
    });
</script>

練習2

完成 TodoList 中點選某個 li 刪除它的功能

<div id="app">
    <input v-model="num" ref="id"/>
    <button @click="add">提交</button>

<ul>
    <todo-item
            v-for="(content, index) in list"
            :key="index"  
            :content="content"   父元件向子元件傳遞資料
            :index="index"
            @delete = "handleDelete" 父元件的訂閱方法
    ></todo-item>
</ul>
</div>
<script>
    // 全域性元件
    Vue.component('todo-item', {
        props : ['content', 'index'], # 子元件接收資料
        template: '<li @click="deleteItem">{{content}}</li>', # 繫結點選事件
        methods:{
            deleteItem:function () {
                this.$emit("delete", this.index); # 子元件向父元件傳送訊息,攜帶該 li 的index 資料
            }
        }
    });

    new Vue({
        el: '#app',
        data: {
            num: "",
            list: []
        },
        methods: {
            add: function () {
                if (this.num) {
                    this.list.push(this.num);
                    this.num = "";
                } else {
                    alert("請輸入要新增的內容後重試!");
                    this.$refs.id.focus();
                }
            },
            handleDelete : function (index) { # 父元件收到訊息後執行刪除方法,刪除對應 index 的 li 標籤
                // alert(index);
                this.list.splice(index, 1);
            }
        }
    });
</script>

Vue 腳手架工具 vue-cli

首先安裝 node.js

1564726440925

下載地址:

https://nodejs.org/en/download/

下載對應系統的版本,雙擊安裝即可。安裝完成後會自動新增全域性變數。使用 node -v 來確認是否安裝成功

安裝 NPM

(Node Package Manager)他是node包管理和分發的工具,使用NPM可以對應用的依賴進行管理,NPM的功能和服務端專案構建工具maven差不多,我們通過npm 可以很方便地下載js庫,打包js檔案。
node.js已經整合了npm工具,在命令提示符輸入 npm -v 可檢視當前npm版本

設定包路徑,

包路徑就是npm從遠端下載的js包所存放的路徑。使用 npm config ls 查詢NPM管理包路徑(NPM下載的依賴包所存放的路徑)

使用下面的命令來設定:

npm config set prefix "C:\develop\nodeJS\npm_modules"
npm config set cache "c:\develop\nodeJS\npm_cache"
  1. 安裝淘寶的映象。映象預設是使用國外的網路來下載的。網速很慢,因此我們配置一個國內的映象
npm install -g cnpm --registry=https://registry.npm.taobao.org

安裝完成後使用:cnpm -v 來檢視

注意:如果安裝後,出現 cnpm 不是內部或外部命令,也不是可執行的程式。就需要檢查cnpm 的路徑是否正確。將 cnpm包的所有檔案複製和 npm.cmd 檔案在同一級目錄下即可。

究其原因:是因為環境變數中僅僅配置了 npm.cmd 所在資料夾路徑,我們也可以將 npm_modules 目錄新增到環境變數中,這樣也不會出現這個問題。推薦使用該方法

新增環境變數:

1564731885562

在 PATH 中新增:

1564731919317

安裝 nrm

cnpm install -g nrm

切換映象

檢視已安裝的映象 : nrm ls 切換映象 nrm use XXX

最後,安裝 vue-cli 客戶端

npm install --global vue-cli

建立新的Vue專案

  1. 建立一個資料夾,用於存放和維護 Vue 專案,這裡我建立的是 c:\develop\VueProjects
  2. 切換到該資料夾,開啟cmd。然後輸入: vue init webpack 專案名
  3. 配置按照下圖設定
    1564734104979

最後一行選項選擇的是包/依賴安裝方式

  1. 建立完成後,切換到專案路徑。使用 npm run dev 命令啟動專案

將專案匯入IDEA

這裡因為我電腦上只有IDEA並且懶得安裝前端程式設計IDE,所以就使用IDEA來程式設計

安裝後會存在一個問題,IDEA 並不能正確識別 .vue 檔案(我是2018.2版本,不知新版解決沒有),因此會將.vue檔案識別成普通文字檔案,給我們編碼帶來很大的不便,解決辦法如圖:

1564735407072

另外,IDEA也不能識別ES6語法,我們也需要進行一些配置:

1564735699406

通過上面的兩個設定,就可以愉快的使用 IDEA 進行 Vue 專案程式設計啦!

Vue-Cli 中編輯的專案是支援熱部署的,耶!

Vue專案結構

專案根目錄下有一個 index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>todolist</title>
  </head>
  <body>
    <div id="app"></div> <!-- 這裡定義了一個 app 的掛載點 -->
    <!-- built files will be auto injected -->
  </body>
</html>

src 目錄下有 main.js 是 Vue 專案的入口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 './App'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  components: { App }, # 這裡採用 ES6 的語法,如果某 key 和 value 是一樣的,可以簡寫成 key
  template: '<App/>'
})

可以看出,入口檔案引入了同目錄下的 App.vue 檔案,那麼這個檔案裡面有什麼內容呢?

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <HelloWorld/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

由此可見,Vue 專案對各個模組進行了拆分,以達到解耦的目的。具體的好處且往下看

練習3

使用 vue-cli 實現 TodoList

  1. 開啟上面建立的 TodoList 專案,修改 App.vue 檔名稱為 TodoList.vue , 並修改其他檔案中的引用名
  2. 編輯 TodoList.vue 的模板檔案,程式碼如下:
<template>
  <div>
    <input>
    <button>提交</button>
  </div>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
</template>

這時開啟瀏覽器會發現報錯了

1565001521769

因此我們對模板檔案進行修改,使用一個 div 包裹上面的兩個標籤,發現瀏覽器可以正常顯示了

資料繫結

在 vue-cli 中,資料繫結採用另外一種語法:此時資料不是直接繫結,而是間接通過函式來返回

<script>
    export default {
      <!-- 以下是 data : function(){} 的縮寫 -->  
      data(){
        return {
          inputValue : ""
        }
      }
    }
</script>

單擊事件

給提交按鈕新增單擊事件:

<button @click="handleClick">提交</button>

定義函式:依然可以採用 ES6 的語法,簡略的寫成 handleClick(){}

<script>
    export default {
      methods:{
        handleClick (){
          alert(123)
        }
      }
    }
</script>

建立子元件

vue-cli 的子元件放在 compontents 目錄下:

1565002961390

  1. 複製一份乾淨的 .vue 程式碼,起名 TodoItem.vue
<template>

</template>

<script>
export default {

}
</script>

<style>

</style>
  1. 新增模板資料,在 TodoList.vue 例項中引入 TodoItem.vue 元件,並註冊
<script>
// 引入元件, import 元件名 from 元件路徑
import TodoItem from './components/TodoItem'

export default {
  // 註冊元件, ‘元件標籤名’:元件名 
  components:{
    'todo-item' : TodoItem
  },
......
  1. 找到合適的位置,新增元件標籤
<ul>
    <todo-item></todo-item>
</ul>

父元件向子元件傳值

通過定義屬性的方式來給子元件傳值

定義 content 屬性,index 屬性傳給子元件

<ul>
    <todo-item
    v-for="(item, index) of list"
        :key="index"
        :content="item"
        :index="index"
    ></todo-item>
</ul>

子元件宣告接收的值:

<script>
    export default {
      props:['content']
    }
</script>

通過插值表示式來顯示值:

<template>
    <li>{{content}}</li>
</template>

子元件向父元件傳值

通過釋出/訂閱的方式來實現子元件向父元件傳值

在子元件的單擊方法中定義釋出訊息的事件,事件名 delete, 引數:當前 li 元素的 index

handleDelete(){
    this.$emit('delete', this.index)
}

父元件接收訊息:並觸發函式的執行

<ul>
      <todo-item
        v-for="(item, index) of list"
        :key="index"
        :content="item"
        :index="index"
        @delete="handleDelete" // 接收訊息
      ></todo-item>
</ul>

handleDelete (index){
    this.list.splice(index, 1) // 刪除對應的元素
}

全域性樣式與區域性樣式

對於每一個 vue 檔案都包含 style 標籤,這個 style 標籤有一個屬性 scoped 如果新增此屬性則該標籤內所有的樣式僅對當前檔案有效。開發中儘量都新增上使得檔案間的耦合性更低

結語

這個筆記僅涵蓋了 Vue 的一點點基礎知識,如果讀者想要深入學習,可以前往官網參考文件繼續學習:https://cn.vuejs.org/v2/guide/

相關文章