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>
處理使用者輸入
元件化
元件:頁面上的某一部分,當一個網頁非常大時,可以將該網頁的內容拆分成幾個部分,便於維護
定義元件
- 定義全域性元件
Vue.component('todo-item', { # 通過 Vue.component('元件名',{元件內容}) 定義元件
template : "<li>Item</li>" # 通過 template 屬性定義元件的內容
});
<ul>
<todo-item></todo-item> <!-- 在頁面以標籤的方式使用元件 -->
</ul>
- 定義區域性元件
// 定義區域性元件
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
需求:如上面的動圖,當輸入框輸入內容後,點選提交就會在下面的列表展示新新增的資料,如果使用者沒有寫任何資料點選提交,提示他應該輸入之後才能點選
<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
下載地址:
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"
- 安裝淘寶的映象。映象預設是使用國外的網路來下載的。網速很慢,因此我們配置一個國內的映象
npm install -g cnpm --registry=https://registry.npm.taobao.org
安裝完成後使用:cnpm -v 來檢視
注意:如果安裝後,出現 cnpm 不是內部或外部命令,也不是可執行的程式。就需要檢查cnpm 的路徑是否正確。將 cnpm包的所有檔案複製和 npm.cmd 檔案在同一級目錄下即可。
究其原因:是因為環境變數中僅僅配置了 npm.cmd 所在資料夾路徑,我們也可以將 npm_modules 目錄新增到環境變數中,這樣也不會出現這個問題。推薦使用該方法
新增環境變數:
在 PATH 中新增:
安裝 nrm
cnpm install -g nrm
切換映象
檢視已安裝的映象 : nrm ls 切換映象 nrm use XXX
最後,安裝 vue-cli 客戶端
npm install --global vue-cli
建立新的Vue專案
- 建立一個資料夾,用於存放和維護 Vue 專案,這裡我建立的是 c:\develop\VueProjects
- 切換到該資料夾,開啟cmd。然後輸入: vue init webpack 專案名
- 配置按照下圖設定
最後一行選項選擇的是包/依賴安裝方式
- 建立完成後,切換到專案路徑。使用 npm run dev 命令啟動專案
將專案匯入IDEA
這裡因為我電腦上只有IDEA並且懶得安裝前端程式設計IDE,所以就使用IDEA來程式設計
安裝後會存在一個問題,IDEA 並不能正確識別 .vue 檔案(我是2018.2版本,不知新版解決沒有),因此會將.vue檔案識別成普通文字檔案,給我們編碼帶來很大的不便,解決辦法如圖:
另外,IDEA也不能識別ES6語法,我們也需要進行一些配置:
通過上面的兩個設定,就可以愉快的使用 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
- 開啟上面建立的 TodoList 專案,修改 App.vue 檔名稱為 TodoList.vue , 並修改其他檔案中的引用名
- 編輯 TodoList.vue 的模板檔案,程式碼如下:
<template>
<div>
<input>
<button>提交</button>
</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</template>
這時開啟瀏覽器會發現報錯了:
因此我們對模板檔案進行修改,使用一個 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 目錄下:
- 複製一份乾淨的 .vue 程式碼,起名 TodoItem.vue
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>
- 新增模板資料,在 TodoList.vue 例項中引入 TodoItem.vue 元件,並註冊
<script>
// 引入元件, import 元件名 from 元件路徑
import TodoItem from './components/TodoItem'
export default {
// 註冊元件, ‘元件標籤名’:元件名
components:{
'todo-item' : TodoItem
},
......
- 找到合適的位置,新增元件標籤
<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/