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/