一、前言:ES6
- ES6 : ECMAScript第6版標準
- ECMA:歐洲計算機制造商協會(
European Association of computer manufacturers
)
1-1、ECMAScript
- 2015年6月,ECMAScript 6,也就是 ECMAScript 2015 發佈了。 並且從 ECMAScript 6 開始,開始採用年號來做版本。即 ECMAScript 2015,就是ECMAScript6
- ECMAScript6 的新特性,更多詳細介紹請移步:阮一峯的ES6教程
1-2、let 和 const 命令
之前,js定義變量只有一個關鍵字:var
,var
有一個問題,就是定義的變量有時會莫名奇妙的成爲全局變量。
例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<script>
for(var i = 0; i < 5; i++){
console.log(i);
}
console.log("循環外:" + i)
</script>
<body>
</body>
</html>
let
所聲明的變量,只在let
命令所在的代碼塊內有效。
我們把剛纔的var
改成let
後執行文件:
const
聲明的變量是常量,不能被修改;
1-3、字符串擴展
ES6爲字符串擴展了幾個新的API:
includes()
:返回布爾值,表示是否找到了參數字符串。startsWith()
:返回布爾值,表示參數字符串是否在原字符串的頭部。endsWith()
:返回布爾值,表示參數字符串是否在原字符串的尾部。
1-4、解構表達式
<!--數組解構-->
<script>
let arr = [1, 2, 3];//定義一個數組
const [x,y,z] = arr;// x,y,z將與arr中的每個位置對應來取值
// 然後打印
console.log(x,y,z);
</script>
<script>
/*對象的解構*/
const person = {//定義一個常量對象
name:"jack",
age:21,
language: ['java','js','css']
}
// 解構表達式獲取值
const {name,age,language} = person;
// 打印
console.log(name);
console.log(age);
console.log(language);
</script>
1-5、函數優化
1、函數參數默認值
<script>
function add(a, b = 1) {
return a + b;
}
// 傳一個參數
console.log(add(10));
</script>
2、箭頭函數(一個參數)
<script>
var print = function (obj) {
console.log(obj);
}
print(123);
// 簡寫爲:
var print2 = obj => console.log(obj);
print2(123);
</script>
3、箭頭函數(兩個參數)
<script>
// 兩個參數的情況:
var sum = function (a , b) {
return a + b;
}
console.log(sum(1,3));
// 簡寫爲:
var sum2 = (a,b) => a+b;
console.log(sum2(2,1));
</script>
代碼不止一行,可以用{}
括起來
<script>
var sum3 = (a,b) => {
return a + b;
}
console.log(sum3(1,2));
</script>
4、對象的函數屬性簡寫:
<script>
let person = {
name: "jack",
// 以前:
eat: function (food) {
console.log(this.name + "在喫" + food);
},
// 箭頭函數版:
eat2: food => console.log(person.name + "在喫" + food),// 這裏拿不到this
// 簡寫版:
eat3(food){
console.log(this.name + "在喫" + food);
}
}
person.eat("漢堡");
person.eat2("薯條");
person.eat3("粥");
</script>
1-6、map和reduce
1、map
map()
:接收一個函數,將原數組中的所有元素用這個函數處理後放入新數組返回。
<script>
let arr = ['1','20','-5','3'];
console.log(arr)
arr = arr.map(s => parseInt(s));
console.log(arr)
</script>
1、reduce
reduce()
:接收一個函數(必須)和一個初始值(可選),該函數接收兩個參數:
- 第一個參數是上一次reduce處理的結果
- 第二個參數是數組中要處理的下一個元素
reduce()
會從左到右依次把數組中的元素用reduce處理,並把處理的結果作爲下次reduce的第一個參數。如果是第一次,會把前兩個元素作爲計算參數,或者把用戶指定的初始值作爲起始參數
<script>
const arr = [1,20,-5,3];
console.log(arr.reduce((a,b) => a+b));/*會執行 1+20-5+3*/
</script>
1-7、promise
所謂Promise,簡單說就是一個容器,裏面保存着某個未來纔會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。
我們可以通過Promise的構造函數來創建Promise對象,並在內部封裝一個異步執行的結果。
語法:
const promise = new Promise(function(resolve, reject) {
// ... 執行異步操作
if (/* 異步操作成功 */){
resolve(value);// 調用resolve,代表Promise將返回成功的結果
} else {
reject(error);// 調用reject,代表Promise會返回失敗結果
}
});
這樣,在promise中就封裝了一段異步執行的結果。
如果我們想要等待異步執行完成,做一些事情,我們可以通過promise的then方法來實現,語法:
promise.then(function(value){
// 異步執行成功後的回調
});
如果想要處理promise異步執行失敗的事件,還可以跟上catch:
promise.then(function(value){
// 異步執行成功後的回調
}).catch(function(error){
// 異步執行失敗後的回調
})
示例:
<script>
const p = new Promise(function (resolve, reject) {
// 這裏我們用定時任務模擬異步
setTimeout(() => {
const num = Math.random();
// 隨機返回成功或失敗
if (num < 0.5) {
resolve("成功!num:" + num)
} else {
reject("出錯了!num:" + num)
}
}, 300)
})
// 調用promise
p.then(function (msg) {
console.log(msg);
}).catch(function (msg) {
console.log(msg);
})
</script>
1-8、set和map
1、set
ES6提供了Set和Map的數據結構。
Set
本質與數組類似。不同在於Set中只能保存不同元素,如果元素相同會被忽略。
構造函數:
// Set構造函數可以接收一個數組或空
let set = new Set();
set.add(1);// [1]
// 接收數組
let set2 = new Set([2,3,4,5,5]);// 得到[2,3,4,5]
普通方法:
- set.add(1);// 添加
- set.clear();// 清空
- set.delete(2);// 刪除指定元素
- set.has(2); // 判斷是否存在
- set.keys();// 返回所有key
- set.values();// 返回所有值
- set.entries();// 返回鍵值對集合
// 因爲set沒有鍵值對,所有其keys、values、entries方法返回值一樣的。 - set.size; // 元素個數。是屬性,不是方法。
2、map
map,本質是與Object類似的結構。不同在於,Object強制規定key只能是字符串。而Map結構的key可以是任意對象。即:
- object是
<string,object>
集合 - map是
<object,object>
集合
構造函數:
// map接收一個數組,數組中的元素是鍵值對數組
const map = new Map([
['key1','value1'],
['key2','value2'],
])
// 或者接收一個set
const set = new Set([
['key1','value1'],
['key2','value2'],
])
const map2 = new Map(set)
// 或者其它map
const map3 = new Map(map);
1-9、模塊化
模塊化就是把代碼進行拆分,方便重複利用。類似java中的導包:要使用一個包,必須先導包。
而JS中沒有包的概念,換來的是 模塊。
模塊功能主要由兩個命令構成:export
和import
。
export
命令用於規定模塊的對外接口,import
命令用於導入其他模塊提供的功能。
1、export
比如:定義一個 hello.js 文件,裏面有一個對象
const util = {
sum(a,b){
return a + b;
}
}
我可以使用export將這個對象導出:
const util = {
sum(a,b){
return a + b;
}
}
export util;
當然,也可以簡寫爲:
export const util = {
sum(a,b){
return a + b;
}
}
export
不僅可以導出對象,一切JS變量都可以導出。比如:基本類型變量、函數、數組、對象。
當要導出多個值時,還可以簡寫。比如我有一個文件:user.js:
var name = "jack"
var age = 21
export {name,age}
上面的導出代碼中,都明確指定了導出的變量名,這樣其它人在導入使用時就必須準確寫出變量名,否則就會出錯。
因此js提供了default
關鍵字,可以對導出的變量名進行省略
例如:
// 無需聲明對象的名字
export default {
sum(a,b){
return a + b;
}
}
這樣,當使用者導入時,可以任意起名字
2、import
使用export
命令定義了模塊的對外接口以後,其他 JS 文件就可以通過import
命令加載這個模塊。
例如我要使用上面導出的util:
// 導入util
import util from 'hello.js'
// 調用util中的屬性
util.sum(1,2)
要批量導入前面導出的name和age:
import {name, age} from 'user.js'
console.log(name + " , 今年"+ age +"歲了")
1-10、對象擴展
ES6給Object拓展了許多新的方法,如:
- keys(obj):獲取對象的所有key形成的數組
- values(obj):獲取對象的所有value形成的數組
- entries(obj):獲取對象的所有key和value形成的二維數組。格式:
[[k1,v1],[k2,v2],...]
- assian(dest, …src) :將多個src對象的值 拷貝到 dest中(淺拷貝)。
1-11、數組擴展
ES6給數組新增了許多方法:
- find(callback):把數組中的元素逐個傳遞給函數callback執行,如果返回true,則返回該元素
- findIndex(callback):與find類似,不過返回的是品牌到的元素的索引
- includes(callback):與find類似,如果匹配到元素,則返回true,代表找到了。
二、Vue 介紹
1、MVVM模式
- M:即Model,模型,包括數據和一些基本操作
- V:即View,視圖,頁面渲染結果
- VM:即View-Model,模型與視圖間的雙向操作(無需開發人員干涉)
在MVVM之前,開發人員從後端獲取需要的數據模型,然後要通過DOM操作Model渲染到View中。而後當用戶操作視圖,我們還需要通過DOM獲取View中的數據,然後同步到Model中。
而MVVM中的VM要做的事情就是把DOM操作完全封裝起來,開發人員不用再關心Model和View之間是如何互相影響的:
- 只要我們Model發生了改變,View上自然就會表現出來。
- 當用戶修改了View,Model中的數據也會跟着改變。
把開發人員從繁瑣的DOM操作中解放出來,把關注點放在如何操作Model上。
Vue 就是一款MVVM模式的框架。
2、Node和NPM
Node.js基於事件循環的異步IO框架
- 基於時間循環的異步IO
- 單線程運行,避免多線程的變量同步問題
- JS可以編寫後臺diamante,前後臺統一編程語言
NPM是Node.js的包管理系統,開發人員可以遵循Common.js規範來編寫Node.js模塊,然後發佈到NPM上供其他開發人員使用。目前已經是世界最大的包模塊管理系統。
官網下載Node.js 並安裝
安裝完成Node應該自帶了NPM了,在控制檯輸入npm -v
查看:
npm默認的倉庫地址是在國外網站,速度較慢,建議大家設置到淘寶鏡像。但是切換鏡像是比較麻煩的。推薦一款切換鏡像的工具:nrm
我們首先安裝nrm,這裏-g
代表全局安裝npm install nrm -g
然後通過nrm ls
命令查看npm的倉庫列表,帶*
的就是當前選中的鏡像倉庫:
通過nrm use taobao
來指定要使用的鏡像源:
然後通過nrm test npm
來測試速度:
注意:
- 安裝完成請一定要重啓下電腦!!!
三、IDEA 安裝 Vue
1、官網下載Vue
解壓得到 Vue.js
2、使用CDN(不推薦)
可以直接使用公共的CDN服務:
<!-- 開發環境版本,包含了用幫助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
或者:
<!-- 生產環境版本,優化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
3、npm安裝(推薦)
在idea的左下角,有個Terminal按鈕,點擊打開控制檯,進入vue_demo01目錄:
先輸入:npm init -y
進行初始化
安裝Vue,輸入命令:npm install vue --save
然後就會在hello-vue目錄發現一個node_modules目錄,並且在下面有一個vue目錄。
node_modules是通過npm安裝的所有模塊的默認位置。
四、Vue入門案例
在vue_demo01目錄新建一個HTML文件 vue01.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h2>{{name}} 非常帥</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
// 生成一個Vue實例
var app = new Vue({
el: "#app", // el,即element。要渲染的的頁面元素
data: { // 數據
name: "Lemon哥"
}
})
</script>
</body>
</html>
打開頁面:
分析:
- 首先通過
new Vue()
來創建Vue實例 - 然後構造函數接收一個對象,對象中有一些屬性:
el
:是element的縮寫,通過id選中要渲染的頁面元素,本例中是一個divdata
:數據,數據是一個對象,裏面有很多屬性,都可以渲染到視圖中name
:這裏我們指定了一個name屬性
- 頁面中的
h2
元素中,我們通過{{name}}的方式,來渲染剛剛定義的name屬性。
雙向綁定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="num">
<h2>
{{name}} 非常帥,
有{{num}}位女神爲他着迷。
</h2>
</div>
<script>
// 生成一個Vue實例
var app = new Vue({
el: "#app", // el,即element。要渲染的的頁面元素
data: { // 數據
name: "周星馳",
num: 1
}
})
</script>
</body>
</html>
- 我們在data添加了新的屬性:
num
- 在頁面中有一個
input
元素,通過v-model
與num
進行綁定。 - 同時通過
{{num}}
在頁面輸出
事件處理
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="num">
<input type="button" v-on:click="num++" value="點擊">
<h2>{{name}},非常帥</h2>
<h2>有{{num}}個粉絲對他着迷</h2>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
name:"周星馳",
num:1
}
})
</script>
</body>
</html>
- 這裏用
v-on
指令綁定點擊事件,而不是普通的onclick
,然後直接操作num - 普通click是無法直接操作num的。
五、Vue 實例
1、創建 Vue 實例
每個 Vue 應用都是通過用 Vue
函數創建一個新的 Vue 實例開始的:
var vm = new Vue({
// 選項
})
在構造函數中傳入一個對象,並且在對象中聲明各種Vue需要的數據和方法,包括:
- el
- data
- methods
2、模板或元素
每個Vue實例都需要關聯一段Html模板,Vue會基於此模板進行視圖渲染。
我們可以通過el屬性來指定。
例如一段html模板:
<div id="app">
</div>
然後創建Vue實例,關聯這個div
var vm = new Vue({
el:"#app"
})
這樣,Vue就可以基於id爲app
的div元素作爲模板進行渲染了。在這個div範圍以外的部分是無法使用vue特性的。
3、數據
當Vue實例被創建時,它會嘗試獲取在data中定義的所有屬性,用於視圖的渲染,並且監視data中的屬性變化,當data發生改變,所有相關的視圖都將重新渲染,這就是“響應式“系統。
html:
<div id="app">
<input type="text" v-model="name"/>
</div>
js:
var vm = new Vue({
el:"#app",
data:{
name:"劉德華"
}
})
- name的變化會影響到
input
的值 - input中輸入的值,也會導致vm中的name發生改變
4、方法
Vue實例中除了可以定義data屬性,也可以定義方法,並且在Vue的作用範圍內使用。
html:
<div id="app">
{{num}}
<button v-on:click="add">加</button>
</div>
js:
var vm = new Vue({
el:"#app",
data:{
num: 0
},
methods:{
add:function(){
// this代表的當前vue實例
this.num++;
}
}
})
5、生命週期鉤子
5-1、生命週期
每個 Vue 實例在被創建時都要經過一系列的初始化過程 :創建實例,裝載模板,渲染模板等等。Vue爲生命週期中的每個狀態都設置了鉤子函數(監聽函數)。每當Vue實例處於不同的生命週期時,對應的函數就會被觸發調用。
生命週期:
5-2、鉤子函數
例如:created代表在vue實例創建後;
我們可以在Vue中定義一個created函數,代表這個時期的構造函數:
html:
<div id="app">
{{hello}}
</div>
js:
var vm = new Vue({
el:"#app",
data:{
hello: '' // hello初始化爲空
},
created(){
this.hello = "hello, world! 我出生了!";
}
})
結果:
5-3、this
我們可以看下在vue內部的this變量是誰,我們在created的時候,打印this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h2>{{hello}}</h2>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
hello: '' // hello初始化爲空
},
created() {
this.hello = "hello, world! 我出生了!";
console.log(this);
}
})
</script>
</body>
</html>
查看控制檯:
六、Vue 指令
指令 (Directives) 是帶有 v-
前綴的特殊特性。指令特性的預期值是:單個 JavaScript 表達式。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。
例如我們在入門案例中的v-on,代表綁定事件。
1、差值表達式
1-1、花括號
格式:
{{表達式}}
說明:
- 該表達式支持JS語法,可以調用js內置函數(必須有返回值)
- 表達式必須有返回結果。例如 1 + 1,沒有結果的表達式不允許使用,如:var a = 1 + 1;
- 可以直接獲取Vue實例中定義的數據或函數
示例:
HTML:
<div id="app">{{name}}</div>
JS:
var app = new Vue({
el:"#app",
data:{
name:"Jack"
}
})
1-2、差值閃爍
使用{{ }}
方式在網速較慢時會出現問題。在數據未加載完成時,頁面會顯示出原始的{{ }}
,加載完畢後才顯示正確數據,我們稱爲插值閃爍。
我們將網速調慢一些,然後試試看剛纔的案例:
1-3、v-text 和 v-html
使用v-text和v-html指令來替代{{}}
說明:
- v-text:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會作爲普通文本輸出
- v-html:將數據輸出到元素內部,如果輸出的數據有HTML代碼,會被渲染
示例:
HTML:
<div id="app">
v-text:<span v-text="hello"></span> <br/>
v-html:<span v-html="hello"></span>
</div>
JS:
var vm = new Vue({
el:"#app",
data:{
hello: "<h1>大家好,我是虎哥</h1>"
}
})
效果:
2、v-model
v-text和v-html可以看做是單向綁定,數據影響了視圖渲染,但是反過來就不行。但是v-model是雙向綁定,視圖(View)和模型(Model)之間會互相影響。
既然是雙向綁定,一定是在視圖中可以修改數據,這樣就限定了視圖的元素類型。目前v-model的可使用元素有:
- input
- select
- textarea
- checkbox
- radio
- components(Vue中的自定義組件)
基本上除了最後一項,其它都是表單的輸入項。
舉例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="checkbox" v-model="language" value="Java" />Java<br/>
<input type="checkbox" v-model="language" value="PHP" />PHP<br/>
<input type="checkbox" v-model="language" value="Swift" />Swift<br/>
<h1>
你選擇了:{{language.join(',')}}
</h1>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
language: []
}
})
</script>
</body>
</html>
- 多個
CheckBox
對應一個model時,model的類型是一個數組,單個checkbox值是boolean類型 - radio對應的值是input的value值
input
和textarea
默認對應的model是字符串select
單選對應字符串,多選對應也是數組
自定義事件也可以用於創建支持 v-model
的自定義輸入組件。記住:
<input v-model="searchText">
等價於:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
3、v-on
3-1、基本用法
v-on指令用於給頁面元素綁定事件。
語法:
v-on:事件名="js片段或函數名"
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="num++">增加</button><br/>
<!--事件指定一個回調函數,必須是Vue實例中定義的函數-->
<button v-on:click="decrement">減少</button><br/>
<h1>num: {{num}}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
num:1
},
methods:{
decrement(){
this.num--;
}
}
})
</script>
效果:
另外,事件綁定可以簡寫,例如v-on:click='add'
可以簡寫爲@click='add'
3-2、事件修飾符
在事件處理程序中調用 event.preventDefault()
或 event.stopPropagation()
是非常常見的需求。儘管我們可以在方法中輕鬆實現這點,但更好的方式是:方法只有純粹的數據邏輯,而不是去處理 DOM 事件細節。
爲了解決這個問題,Vue.js 爲 v-on
提供了事件修飾符。修飾符是由點開頭的指令後綴來表示的。
.stop
:阻止事件冒泡.prevent
:阻止默認事件發生.capture
:使用事件捕獲模式.self
:只有元素自身觸發事件才執行。(冒泡或捕獲的都不執行).once
:只執行一次
3-3、按鈕修飾符
在監聽鍵盤事件時,我們經常需要檢查常見的鍵值。Vue 允許爲 v-on
在監聽鍵盤事件時添加按鍵修飾符:
<!-- 只有在 `keyCode` 是 13 時調用 `vm.submit()` -->
<input v-on:keyup.13="submit">
記住所有的 keyCode
比較困難,所以 Vue 爲最常用的按鍵提供了別名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 縮寫語法 -->
<input @keyup.enter="submit">
全部的按鍵別名:
.enter
.tab
.delete
(捕獲“刪除”和“退格”鍵).esc
.space
.up
.down
.left
.right
3-4、組合按鈕
可以用如下修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器。
.ctrl
.alt
.shift
例如:
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
4、v-for
遍歷數據渲染頁面是非常常用的需求,Vue中通過v-for指令來實現。
4-1、遍歷數組
語法:
v-for="item in items"
- items:要遍歷的數組,需要在vue的data中定義好。
- item:迭代得到的數組元素的別名
示例
<div id="app">
<ul>
<li v-for="user in users">
{{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
users:[
{name:'柳巖', gender:'女', age: 21},
{name:'虎哥', gender:'男', age: 30},
{name:'范冰冰', gender:'女', age: 24},
{name:'劉亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
}
})
</script>
效果:
4-2、數組角標
在遍歷的過程中,如果我們需要知道數組角標,可以指定第二個參數:
語法:
v-for="(item,index) in items"
- items:要迭代的數組
- item:迭代得到的數組元素別名
- index:迭代到的當前元素索引,從0開始。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(user,index) in users">
{{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
users:[
{name:'柳巖', gender:'女', age: 21},
{name:'虎哥', gender:'男', age: 30},
{name:'范冰冰', gender:'女', age: 24},
{name:'劉亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
}
})
</script>
</body>
</html>
效果:
4-3、遍歷對象
v-for除了可以迭代數組,也可以迭代對象。語法基本類似
語法:
v-for="value in object"
v-for="(value,key) in object"
v-for="(value,key,index) in object"
- 1個參數時,得到的是對象的值
- 2個參數時,第一個是值,第二個是鍵
- 3個參數時,第三個是索引,從0開始
示例:
<div id="app">
<ul>
<li v-for="(value,key,index) in user">
{{index}} - {{key}} : {{value}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
user:{name:'柳巖', gender:'女', age: 21}
}
})
</script>
效果:
4-4、key
當 Vue.js 用 v-for
正在更新已渲染過的元素列表時,它默認用“就地複用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單複用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
這個功能可以有效的提高渲染的效率。
但是要實現這個功能,你需要給Vue一些提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要爲每項提供一個唯一 key
屬性。理想的 key
值是每項都有的且唯一的 id。
示例:
<ul>
<li v-for="(item,index) in items" :key=index></li>
</ul>
- 這裏使用了一個特殊語法:
:key=""
,它可以讓你讀取vue中的屬性,並賦值給key屬性 - 這裏我們綁定的key是數組的索引,應該是唯一的
5、v-if 和 v-show
5-1、基本用法
v-if
,顧名思義,條件判斷。當得到結果爲true時,所在的元素纔會被渲染。
語法:
v-if="布爾表達式"
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="show = !show">點擊切換</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true
}
})
</script>
效果:
5-2、與 v-for 結合
當v-if和v-for出現在一起時,v-for優先級更高。也就是說,會先遍歷,再判斷條件。
示例:
<div id="app">
<ul>
<li v-for="(user,index) in users" v-if="user.gender === '女'">
{{index}} - {{user.name}} : {{user.gender}} : {{user.age}}
</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
users:[
{name:'柳巖', gender:'女', age: 21},
{name:'虎哥', gender:'男', age: 30},
{name:'范冰冰', gender:'女', age: 24},
{name:'劉亦菲', gender:'女', age: 18},
{name:'古力娜扎', gender:'女', age: 25}
]
}
})
</script>
效果:
5-3、v-else
你可以使用 v-else
指令來表示 v-if
的“else 塊”:
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
v-else
元素必須緊跟在帶 v-if
或者 v-else-if
的元素的後面,否則它將不會被識別。
v-else-if
,顧名思義,充當 v-if
的“else-if 塊”,可以連續使用:
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
類似於 v-else
,v-else-if
也必須緊跟在帶 v-if
或者 v-else-if
的元素之後。
5-4、v-show
另一個用於根據條件展示元素的選項是 v-show
指令。用法大致一樣:
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show
的元素始終會被渲染並保留在 DOM 中。v-show
只是簡單地切換元素的 CSS 屬性 display
。
示例:
<div id="app">
<!--事件中直接寫js片段-->
<button v-on:click="show = !show">點擊切換</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true
}
})
</script>
效果:
6、v-bind
6-1、綁定 class 樣式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
<style>
.a {
color: red;
}
.b {
background-color: aqua;
}
</style>
</head>
<body>
<div id="app">
<h1 v-bind:class="a">你好</h1>
<h1 v-bind:class="b">你好</h1>
<h1 v-bind:class="arr">你好</h1>
<h1 :class="arr">你好</h1><!--等同於上面的-->
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
arr:['a','b'],
a : 'a',
b : 'b'
}
})
</script>
</body>
</html>
6-2、簡寫
v-bind:class
可以簡寫爲:class
7、計算屬性
在插值表達式中使用js表達式是非常方便的,而且也經常被用到。
但是如果表達式的內容很長,就會顯得不夠優雅,而且後期維護起來也不方便,例如下面的場景,我們有一個日期的數據,但是是毫秒值:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>您的生日是:{{
new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
}}
</h1>
</div>
<script>
var v = new Vue({
el:"#app",
data:{
birthday:1529032123201 // 毫秒值
}
})
</script>
</body>
</html>
雖然能得到結果,但是非常麻煩。
Vue中提供了計算屬性,來替代複雜的表達式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<h1>您的生日是:{{birth}} </h1>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
birthday: 1429032123201 // 毫秒值
},
computed: {
birth() {// 計算屬性本質是一個方法,但是必須返回結果
const d = new Date(this.birthday);
return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
}
}
})
</script>
</body>
</html>
8、watch
watch可以讓我們監控一個值的變化。從而做出相應的反應。
雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是爲什麼 Vue 通過 watch
選項提供了一個更通用的方法,來響應數據的變化。當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
message: ""
},
watch: {
message(newVal, oldVal) {
console.log(newVal, oldVal);
}
}
})
</script>
</body>
</html>
七、Vue 組件化
在大型應用開發的時候,頁面可以劃分成很多部分。往往不同的頁面,也會有相同的部分。例如可能會有相同的頭部導航。
但是如果每個頁面都獨自開發,這無疑增加了我們開發的成本。所以我們會把頁面的不同部分拆分成獨立的組件,然後在不同頁面就可以共享這些組件,避免重複開發。
1、定義全局組件
我們通過Vue的component方法來定義一個全局組件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--使用定義好的全局組件-->
<counter></counter>
</div>
<script type="text/javascript">
// 定義全局組件,兩個參數:1,組件名稱。2,組件參數
Vue.component("counter", {
template: '<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
data() {
return {
count: 0
}
}
})
var app = new Vue({
el: "#app"
})
</script>
</body>
</html>
- 組件其實也是一個Vue實例,因此它在定義時也會接收:data、methods、生命週期函數等
- 不同的是組件不會與頁面的元素綁定,否則就無法複用了,因此沒有el屬性。
- 但是組件渲染需要html模板,所以增加了template屬性,值就是HTML模板
- 全局組件定義完畢,任何vue實例都可以直接在HTML中通過組件名稱來使用組件了。
- data的定義方式比較特殊,必須是一個函數。
效果:
2、局部註冊
一旦全局註冊,就意味着即便以後你不再使用這個組件,它依然會隨着Vue的加載而加載。
因此,對於一些並不頻繁使用的組件,我們會採用局部註冊。
我們先在外部定義一個對象,結構與創建組件時傳遞的第二個參數一致:
const counter = {
template:'<button v-on:click="count++">你點了我 {{ count }} 次,我記住了.</button>',
data(){
return {
count:0
}
}
};
然後在Vue中使用它:
var app = new Vue({
el:"#app",
components:{
counter:counter // 將定義的對象註冊爲組件
}
})
- components就是當前vue對象子組件集合。
- 其key就是子組件名稱
- 其值就是組件對象的屬性
- 效果與剛纔的全局註冊是類似的,不同的是,這個counter組件只能在當前的Vue實例中使用
3、組件通信
通常一個單頁應用會以一棵嵌套的組件樹的形式來組織:
- 頁面首先分成了頂部導航、左側內容區、右側邊欄三部分
- 左側內容區又分爲上下兩個組件
- 右側邊欄中又包含了3個子組件
各個組件之間以嵌套的關係組合在一起,那麼這個時候不可避免的會有組件間通信的需求。
3-1、父向子傳遞 props
比如我們有一個子組件:
Vue.component("introduce",{
// 直接使用props接收到的屬性來渲染頁面
template:'<h3>{{title}}</h3>',
props:[title] // 通過props來接收一個父組件傳遞的屬性
})
- 這個子組件中要使用title屬性渲染頁面,但是自己並沒有title屬性
- 通過props來接收父組件屬性,名爲title
父組件使用子組件,同時傳遞title屬性:
<div id="app">
<h1>打個招呼:</h1>
<!--使用子組件,同時傳遞title屬性-->
<introduce title="大家好,我是虎哥"/>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component("introduce",{
// 直接使用props接收到的屬性來渲染頁面
template:'<h1>{{title}}</h1>',
props:['title'] // 通過props來接收一個父組件傳遞的屬性
})
var app = new Vue({
el:"#app"
})
</script>
3-2、傳遞複雜數據
我們定義一個子組件:
const myList = {
template:'\
<ul>\
<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
</ul>\
',
props:{ // 通過props來接收父組件傳遞來的屬性
items:{// 這裏定義items屬性
type:Array,// 要求必須是Array類型
default:[] // 如果父組件沒有傳,那麼給定默認值是[]
}
}
}
- 這個子組件可以對 items 進行迭代,並輸出到頁面。
- 但是組件中並未定義items屬性。
- 通過props來定義需要從父組件中接收的屬性
- items:是要接收的屬性名稱
- type:限定父組件傳遞來的必須是數組,否則報錯
- default:默認值
- items:是要接收的屬性名稱
我們在父組件中使用它:
<div id="app">
<h2>已開設如下課程:</h2>
<!-- 使用子組件的同時,傳遞屬性,這裏使用了v-bind,指向了父組件自己的屬性lessons -->
<my-list :items="lessons"/>
</div>
var app = new Vue({
el:"#app",
components:{
myList // 當key和value一樣時,可以只寫一個
},
data:{
lessons:[
{id:1, name: 'java'},
{id:2, name: 'php'},
{id:3, name: 'ios'},
]
}
})
3-3、子向父的通信
來看這樣的一個案例:
<div id="app">
<h2>num: {{num}}</h2>
<!--使用子組件的時候,傳遞num到子組件中-->
<counter :num="num"></counter>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component("counter", {// 子組件,定義了兩個按鈕,點擊數字num會加或減
template:'\
<div>\
<button @click="num++">加</button> \
<button @click="num--">減</button> \
</div>',
props:['num']// count是從父組件獲取的。
})
var app = new Vue({
el:"#app",
data:{
num:0
}
})
</script>
- 子組件接收父組件的num屬性
- 子組件定義點擊按鈕,點擊後對num進行加或減操作
子組件接收到父組件屬性後,默認是不允許修改的。怎麼辦?
既然只有父組件能修改,那麼加和減的操作一定是放在父組件:
var app = new Vue({
el:"#app",
data:{
num:0
},
methods:{ // 父組件中定義操作num的方法
increment(){
this.num++;
},
decrement(){
this.num--;
}
}
})
但是,點擊按鈕是在子組件中,那就是說需要子組件來調用父組件的函數,怎麼做?
我們可以通過v-on指令將父組件的函數綁定到子組件上:
<div id="app">
<h2>num: {{num}}</h2>
<counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>
然後,當子組件中按鈕被點擊時,調用綁定的函數:
Vue.component("counter", {
template:'\
<div>\
<button @click="plus">加</button> \
<button @click="reduce">減</button> \
</div>',
props:['count'],
methods:{
plus(){
this.$emit("inc");
},
reduce(){
this.$emit("dec");
}
}
})
- vue提供了一個內置的this.$emit函數,用來調用父組件綁定的函數
八、路由 vue-router
1、vue-router簡介和安裝
使用npm安裝:npm install vue-router --save
在index.html中引入依賴:
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
2、入門實例
1、編寫父組件 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<span>登錄</span>
<span>註冊</span>
<hr/>
<div>
登錄頁/註冊頁
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app"
})
</script>
</body>
</html>
2、編寫登錄組件 js/login.js
const loginForm = {
template:'\
<div>\
<h2>登錄頁</h2> \
用戶名:<input type="text"><br/>\
密碼:<input type="password"><br/>\
</div>\
'
}
3、編寫註冊組件 js/register.js
const registerForm = {
template:'\
<div>\
<h2>註冊頁</h2> \
用戶名:<input type="text"><br/>\
密碼:<input type="password"><br/>\
確認密碼:<input type="password"><br/>\
</div>\
'
}
4、修改父組件 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script src="js/login.js"></script>
<script src="js/register.js"></script>
</head>
<body>
<div id="app">
<span>登錄</span>
<span>註冊</span>
<hr/>
<div>
<login-form></login-form>
<register-form></register-form>
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
components:{// 引用登錄和註冊組件
loginForm,
registerForm
}
})
</script>
</body>
</html>
5、再次修改父組件 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主頁</title>
<script src="../node_modules/vue/dist/vue.js"></script>
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
<script src="js/login.js"></script><!--引用登錄組件-->
<script src="js/register.js"></script><!--引用註冊組件-->
</head>
<body>
<div id="app">
<!--router-link來指定跳轉的路徑-->
<span><router-link to="/login">登錄</router-link></span>
<span><router-link to="/register">註冊</router-link></span>
<hr/>
<div>
<!--vue-router的錨點-->
<router-view></router-view>
</div>
</div>
<script type="text/javascript">
// 創建VueRouter對象
const router = new VueRouter({
routes:[ // 編寫多個路由規則
{
path:"/login", // 請求路徑
component:loginForm // 組件名稱
},
{path:"/register",component:registerForm},
]
})
var vm = new Vue({
el:"#app",
components:{// 引用登錄和註冊組件
loginForm,
registerForm
},
router:router // 引用上面定義的router對象
})
</script>
</body>
</html>
-
創建VueRouter對象,並指定路由參數
-
routes:路由規則的數組,可以指定多個對象,每個對象是一條路由規則,包含以下屬性:
- path:路由的路徑
- component:組件名稱
-
通過
<router-view>
來指定一個錨點,當路由的路徑匹配時,vue-router會自動把對應組件放到錨點位置進行渲染 -
通過
<router-link>
指定一個跳轉鏈接,當點擊時,會觸發vue-router的路由功能,路徑中的hash值會隨之改變
注意:單頁應用中,頁面的切換並不是頁面的跳轉。僅僅是地址最後的hash值變化。
事實上,總共就一個HTML:index.html
九、webpack
1、webpack 概述
Webpack 是一個前端資源的打包工具,它可以將js、image、css等資源當成一個模塊進行打包。
爲什麼需要打包?
- 將許多碎小文件打包成一個整體,減少單頁面內的衍生請求次數,提高網站效率。
- 將ES6的高級語法進行轉換編譯,以兼容老版本的瀏覽器。
- 將代碼打包的同時進行混淆,提高代碼的安全性。
2、webpack 四個核心概念
-
入口(entry)
webpack打包的啓點,可以有一個或多個,一般是js文件。webpack會從啓點文件開始,尋找啓點直接或間接依賴的其它所有的依賴,包括JS、CSS、圖片資源等,作爲將來打包的原始數據
-
輸出(output)
出口一般包含兩個屬性:path和filename。用來告訴webpack打包的目標文件夾,以及文件的名稱。目的地也可以有多個。
-
加載器(loader)
webpack本身只識別Js文件,如果要加載非JS文件,必須指定一些額外的加載器(loader),例如css-loader。然後將這些文件轉爲webpack能處理的有效模塊,最後利用webpack的打包能力去處理。
-
插件(plugins)
插件可以擴展webpack的功能,讓webpack不僅僅是完成打包,甚至各種更復雜的功能,或者是對打包功能進行優化、壓縮,提高效率。
3、webpack 本地安裝
輸入命令:npm install webpack webpack-cli --save-dev
此時,我們注意下項目中文件夾下,會有一個package.json文件。(其實早就有了)打開文件,可以看到我們之前用npm安裝過的文件都會出現在這裏:
4、編寫webpack配置
接下來,我們編寫一個webpack的配置,來指定一些打包的配置項。配置文件的名稱,默認就是webpack.config.js,我們放到vue-demo01的根目錄:
配置文件中就是要指定上面說的四個核心概念,入口、出口、加載器、插件。
不過,加載器和插件是可選的。我們先編寫入口和出口
4-1、入口entry
webpack打包的啓點,可以有一個或多個,一般是js文件。現在思考一下我們有沒有一個入口?貌似沒有,我們所有的東西都集中在index.html,不是一個js,那怎麼辦?
我們新建一個js,把index.html中的部分內容進行集中,然後在index.html中引用這個main.js不就OK了!
然後把原來index.html中的js代碼全部移動到main.js中
// 使用es6的語法導入js模塊
import Vue from '../node_modules/vue/dist/vue';
import VueRouter from '../node_modules/vue-router/dist/vue-router'
import loginForm from './js/login'
import registerForm from './js/register'
Vue.use(VueRouter)
// 創建VueRouter對象
const router = new VueRouter({
routes:[ // 編寫多個路由規則
{
path:"/login", // 請求路徑
component:loginForm // 組件名稱
},
{path:"/register",component:registerForm},
]
})
var vm = new Vue({
el:"#app",
components:{// 引用登錄和註冊組件
loginForm,
registerForm
},
router
})
-
原來的index.html中引入了很多其它js,在這裏我們使用es6的import語法進行導入。
注意,要使用import,就需要在login.js和register.js中添加export導出語句:
const loginForm = {
template:`
<div>
<h2>登錄頁</h2>
用戶名:<input type="text"><br/>
密碼:<input type="password"><br/>
</div>
`
}
export default loginForm;
register.js:
const registerForm = {
template:`
<div>
<h2>註冊頁</h2>
用戶名:<input type="text"><br/>
密碼:<input type="password"><br/>
確認密碼:<input type="password"><br/>
</div>
`
}
export default registerForm;
- vue-router使用模塊話加載後,必須增加一句:Vue.use(VueRouter)
這樣,main.js就成了我們整個配置的入口了。
我們在webpack.config.js中添加以下內容:
module.exports={
entry:'./src/main.js', //指定打包的入口文件
}
4-2、出口output
出口,就是輸出的目的地。一般我們會用一個dist目錄,作爲打包輸出的文件夾:
然後,編寫webpack.config.js,添加出口配置:
module.exports={
entry:'./src/main.js', //指定打包的入口文件
output:{
// path: 輸出的目錄,__dirname是相對於webpack.config.js配置文件的絕對路徑
path : __dirname+'/dist',
filename:'build.js' //輸出的js文件名
}
}
4-3、執行打包
在控制檯輸入以下命令:
npx webpack --config webpack.config.js