[toc]
邂逅Vue.js
1.編程范式
- 命令式編程 如jquery
- 聲明式編程 只需要生命需要顯示的東西就可以
- 創(chuàng)建Vue實(shí)例的時(shí)候侥猬,傳入了一個(gè)對象options泵喘,這個(gè)opentions中包含了
- el: 類型:string|HTMLElement 作用:決定之后Vue實(shí)例會管理哪一個(gè)DOM
- data: 類型:Object|Function(組件中data必須是一個(gè)函數(shù)) 作用:Vue實(shí)例對應(yīng)的數(shù)據(jù)對象
- methods: 類型:{[key: string] : Function} 作用: 定義屬于Vue的一些方法仗岸,可以在其他地方調(diào)用歪赢,也可以在指令中使用廉涕。
Vue基礎(chǔ)語法
- 前端代碼縮進(jìn)最好兩個(gè)空格睬澡,多數(shù)大型開源框架都是兩個(gè)
模板語法
Mustache語法({{}})
- 可以寫變量雀哨,也可以寫簡單的表達(dá)式
{{message}} {{firstName + ' ' + lastName}}
指令
- v-once
- 該指令后面不需要跟任何表達(dá)式
- 該指令表示元素和組件只渲染一次磕谅,不會隨數(shù)據(jù)的改變而改變<h2 v-once>{{message}}<h2>
- v-html
- 該指令后面往往會跟上一個(gè)string類型
- 會將string的html解析出來并且進(jìn)行渲染<h2 v-html='url'><h2> data:{ url: '<a }
- v-text
一般不用,不夠靈活雾棺,會覆蓋innerHTML內(nèi)容{{message}} <h2 v-text='message'><h2>
- v-pre , 原生顯示
<h2 v-pre>{{message}}</h2>
- v-cloak
- 在vue解析之前膊夹,div中有一個(gè)屬性v-cloak
- 在vue解析之后,div中的v-cloak屬性被刪除
- 主要是用來防止界面上顯示未渲染的代碼<div id='app'>{{message}}<div> <script> new Vue({ el: '#app', data{ message: 'aaa' } }) </script> <style> [v-cloak] { display: none } </style>
- v-bind
- 動態(tài)綁定屬性
- 縮寫: ':'
- 預(yù)期: any(with argument) | Object(without argument)
- 參數(shù): attrOrProp(optional)<img v-bind:src='imgUrl'> 語法糖寫法 <img :src='imgUrl'> <h1 :class = '{class1(類名): showClass1(bool值), class2: showClass2}'><h1> <h1 :class = 'getClass()'><h1> methods:{ getClass: function(){ return {class1: showClass1, class2: showClass2} } }
- v-bind:style
- 動態(tài)綁定樣式
-<h2 :style="{fontSize: '50px'}"></h2>
-<h2 style="{fontSize: finalSize + 'px'}"></h2>
計(jì)算屬性
- 數(shù)據(jù)展示前需要進(jìn)行處理時(shí)使用捌浩。
computed:{ fullName: function(){ return this.firstName + this.lastName } }
- 計(jì)算屬性會緩存放刨,多次調(diào)用只會計(jì)算一次,方法不會緩存
- 計(jì)算屬性的getter和setter(set不常用)
computed: { fullName: { get: function(){ return this.firstName + ' ' + this.lastName }, set: function(name){ this.fullName = name } } }
對象字面量增強(qiáng)寫法
// 普通寫法
name = 'aaa'
age = 18
const obj = {
name: name,
age: age
}
// 增強(qiáng)寫法
const obj = {
name,
age
}
事件監(jiān)聽
- v-on
- 作用: 綁定事件監(jiān)聽器
- 縮寫: @
- 預(yù)期: Function| Inline Statement | Object
- 參數(shù): event - 參數(shù)傳遞
- 如果方法不需要額外參數(shù)尸饺,那么方法后的()可以不添加
- 如果方法本身有參數(shù)进统,但是調(diào)用的時(shí)候沒有傳遞,省略小括號浪听,默認(rèn)會將event參數(shù)傳遞進(jìn)去
- 如果同時(shí)需要傳入某個(gè)參數(shù)螟碎,同時(shí)需要event,可以通過$event傳入事件<button @click="btnClick"></button> 默認(rèn)傳過去event <button @click="btnClick()"></button> 默認(rèn)傳過去undefined <button @click="btn1Click('aaa',$event)"></button> methods:{ btnClick(aaa){ console.log(aaa) }, btn1Click(aaa, event){ console.log(aaa) } }
- v-on修飾符的使用
- .stop 阻止冒泡<div @click='divClick'> <button @click.stop="btnClick"></button> </div>
- prevent 阻止默認(rèn)事件
<form action="baidu" @click.prevent="submitClick"> </form> # 阻止默認(rèn)提交事件
- .{keyCode | keyAlias} 只當(dāng)事件是從特定鍵觸發(fā)時(shí)才觸發(fā)回調(diào) - .native 監(jiān)聽根元素的原生事件 - .once 只觸發(fā)一次回調(diào)
條件判斷
- v-if
- v-else-if
- v-else
- vue內(nèi)部會復(fù)用dom元素迹栓,如果不想讓復(fù)用掉分,可以加個(gè)key
- v-show
- v-show dom會渲染,使用樣式?jīng)Q定是否顯示
- v-if 根據(jù)條件判斷是否要渲染
- 頻繁切換使用v-show
循環(huán)
-
v-for遍歷
官方推薦在使用v-for遍歷時(shí)迈螟,給對應(yīng)的元素或組件加上一個(gè):key屬性
為什么要使用key屬性叉抡?
假設(shè)有一個(gè)數(shù)組,現(xiàn)在想在數(shù)組中間插入一個(gè)元素答毫,如果沒有key褥民,則插入位置以及后面的位置都需要改變,而如果有key洗搂,則會先使用key與元素對應(yīng)起來消返,插入時(shí)只修改插入位置即可。key必須與item一一對應(yīng)耘拇,所以不能用index撵颊。
遍歷時(shí)key的作用
- 使用key給每一個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識
- Diff算法可以正確的識別此節(jié)點(diǎn)
- 找到正確的位置插入新的節(jié)點(diǎn)
==key的作用主要是為了更高效的更新虛擬DOM==
- 哪些數(shù)組的方法是響應(yīng)式的?
- push(): 可以添加多個(gè) arr.push('aaa', 'bbb', 'ccc')
- pop(): 刪除數(shù)組的最后一個(gè)元素
- shift() : 刪除數(shù)組第一個(gè)元素
- unshift(): 在數(shù)組前面添加元素惫叛, 可以添加多個(gè)
- sort():
- reverse()
- splice() : 刪除元素/插入元素/替換元素 會影響原始數(shù)組
第一個(gè)參數(shù)start倡勇,表示開始操作的索引
刪除元素: 第二個(gè)參數(shù)表示要刪除幾個(gè)元素,如果沒有傳嘉涌,表示刪除所有
替換元素: 第二個(gè)參數(shù)表示要替換的個(gè)數(shù)妻熊,后面參數(shù)表示要替換的元素
插入元素: 第二個(gè)參數(shù)為0夸浅,后面參數(shù)為添加的元素arr = [1,2,3,4,5] arr.splice(1) => [2,3,4,5] arr = [1,2,3,4,5] arr.splice(1,2)? [2,3] arr = [1,2,3,4,5] arr.splice(1,2,'m','n', 'o') => [1, "m", "n", "o", 4, 5] arr = [1,2,3,4,5] arr.splice(1,0,'m', 'n')==> [1, "m", "n", 2, 3, 4, 5]
==通過數(shù)組索引直接修改元素不是響應(yīng)式的, 直接修改界面不會更新==
- Vue.set(obj, index, newValue)
Vue.set(arr, 0, ''a)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h2 v-show="books.length==0">購物車為空</h2>
<table v-show="books.length!=0">
<tr>
<th>書籍名稱</th>
<th>出版日期</th>
<th>價(jià)格</th>
<th>購買數(shù)量</th>
<th>操作</th>
</tr>
<tr v-for="(book, index) in books" :key='book.bookName'>
<td>{{book.bookName}}</td>
<td>{{book.publishDate}}</td>
<td>{{book.price | transPrice}} </td>
<td><button @click="increment(index)">+</button>{{book.number}}<button @click="decrement(index)">-</button></td>
<td><button @click="remove(index)">移除</button></td>
</tr>
</table>
<p>總價(jià):¥{{totalPrice | transPrice}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{'bookName': '《算法導(dǎo)論》', 'publishDate': '2006-9', 'price': 85.00, 'number': 0},
{'bookName': '《UNIX變成藝術(shù)》', 'publishDate': '2006-2', 'price': 59.00, 'number': 0},
{'bookName': '《編程珠璣》', 'publishDate': '2008-10', 'price': 39.00, 'number': 0},
{'bookName': '《代碼大全》', 'publishDate': '2006-12', 'price': 128.00, 'number': 0}
],
},
computed: {
totalPrice(){
let result = this.books.reduce(function(preValue, book){
return preValue + book.price * book.number
}, 0)
return result;
}
},
methods:{
increment(index, book){
this.books[index].number--;
},
decrement(index, book){
this.books[index].number--;
},
remove(index){
this.books.splice(index,1);
}
},
filters: {
transPrice(price){
if(typeof(price)=='number'){
return price.toFixed(2);
}
}
}
})
</script>
- 高階函數(shù)
- filter() : filter回調(diào)函數(shù)必須返回一個(gè)bool值
- map()
- reduce(): 對數(shù)組中所有內(nèi)容進(jìn)行匯總arr = [1,2,3,4] arr.reduce(function(preValue, n){ return preValue + n; }, 0) 0 表示preValue的初始值扔役, n表示每次遍歷時(shí)的元素
- 表單綁定v-model
- v-model其實(shí)是一個(gè)語法糖帆喇,他的背后本質(zhì)包含兩個(gè)操作
- v-bind綁定一個(gè)value屬性
- v-on指令給當(dāng)前元素綁定input事件<input type='text' v-model='message'> 相當(dāng)于 <input type='text', :value='message' @input='message= $event.target.value'> 相當(dāng)于 <input type='text' value='message' @input='changeMessage'> methods:{ changeMessage(event){ this.message = event.target.value; } }
- v-model結(jié)合radio
<label for="male"> <input type="radio" id="male" value="男" v-model='sex'>男 </label> <label for="female"> <input type="radio" id="female" value="女" v-model='sex'>女 </label> data{ sex: '男' }
- v-model結(jié)合checkbox
<!-- 單選 --> <label for="license"> <input type="checkbox" id="license" v-model='isAgree'>同意協(xié)議 </label> <button :disabled='!isAgree'>下一步</button> data{ isAgree: false } <div> <!-- 多選 --> <input type="checkbox" value="籃球" v-model="hobbies">籃球 <input type="checkbox" value="足球" v-model="hobbies">足球 <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球 <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球 </div> data{ hobbies: [] }
- v-select :單選(字符串) 多選(數(shù)組)
- v-model 修飾符
- .lazy<input type="text" v-model.lazy="message">
敲回車或失去焦點(diǎn)才同步數(shù)據(jù)
- .number<input type="number" v=model.number="age">
- .trim<input type="text" v-model.trim="message">
組件化開發(fā)
組件注冊步驟
- 創(chuàng)建組件構(gòu)造器對象
- 注冊組件
- 使用組件
const cpn = Vue.extend({ template: `<div><h2>hhhhh</h2></div>` }) Vue.components('my-cpn', cpn)
- 全局組件和局部組件
- 全局組件可以在多個(gè)Vue實(shí)例中使用
- 局部組件const app = new Vue({ el: '#app', data:{} conponents: { cpn: cpn #局部組件 } }
- 父組件和子組件
- 注冊組件語法糖, 主要時(shí)省去了調(diào)用Vue.extend()的步驟,而是直接可以使用一個(gè)對象來代替
// 全局 Vue.components('cpn', { template: `<div><h2>hhhhh</h2></div>` })
組件間的通信
父子組件的通信
- 通過props向子組件傳遞數(shù)據(jù)
<div id="app">
<cpn :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="movie of cmovies" :key="movie">{{movie}}</li>
</ul>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
movies: ['aaa', 'bbb', 'ccc'],
message: 'hello world'
},
components: {
'cpn': {
template: '#cpn',
data(){
return{
}
},
// props: ['cmovies']
// props:{
// cmovies: Array
// }
props:{
cmovies: {
type: Array,
default(){
return [1,2,3]
}
required: true
}
}
}
}
})
</script>
==props里面如果是駝峰式寫法亿胸,在v-bind用的時(shí)候要使用-連接==
cMovies ---> :c-movies="movies"
- 通過事件向父組件發(fā)送消息
- 在子組件中坯钦,通過$emit()來觸發(fā)事件
- 在父組件中,通過v-on來監(jiān)聽子組件事件
<div id="app">
<cpn :cmovies="movies" @item-click="cpnClick"></cpn>
</div>
<template id="cpn">
<div>
<button v-for="movie of cmovies" :key="movie" @click="itemClick(movie)">{{movie}}</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
movies: ['aaa', 'bbb', 'ccc'],
message: 'hello world'
},
methods:{
cpnClick(item){
console.log(item);
}
},
components: {
'cpn': {
template: '#cpn',
data(){
return{
}
},
methods: {
itemClick(item){
this.$emit('item-click', item)
}
}
}
}
})
</script>
父子組件的訪問方式
- 父組件訪問子組件:使用$children或$refs
this.$children 是一個(gè)數(shù)組侈玄,包含了所有的子組件<child refs='aaa'></child> 在父組件中使用this.$refs.aaa獲取對應(yīng)子組件
- 子組件訪問父組件:使用$parent
- 訪問根組件$root
插槽(slot)
- 組件的插槽是為了讓封裝的組件更加有擴(kuò)展性
- 讓使用者可以決定組件內(nèi)部的一些內(nèi)容到底展示什么
- 插槽的基本使用
<slot></slot>
- 插槽的默認(rèn)值
<slot><button>按鈕</button></slot>
- 如果有多個(gè)值婉刀,同時(shí)放到組件中替換,一起作為替換元素
具名插槽
<cpn>
<button slot='left'><button>
<cpn>
<template id='cpn'>
<slot name='left'></slot>
<slot name='center'></slot>
<slot name='right'></slot>
</template>
作用域插槽
父組件替換插槽的標(biāo)簽序仙,但是內(nèi)容由子組件來提供
<div id="app">
<cpn>
<template slot-scope='slot'>
<span>{{slot.data.join('-')}}</span>
</template>
</cpn>
<cpn>
<template slot-scope='slot'>
<span>{{slot.data.join('*')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<slot :data='languages'>
<ul>
<li v-for="item of languages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data(){
return {
}
},
components: {
cpn: {
template: '#cpn',
data(){
return {
languages: ['aaa', 'bbb', 'ccc', 'ddd']
}
}
}
}
})
</script>
模塊化開發(fā)
模塊化有兩個(gè)核心:導(dǎo)出和導(dǎo)入
CommonJs的導(dǎo)出
moduleA.exports = {
flag: true,
sum(a,b){
return a + b
}
}
CommonJS的導(dǎo)入
let {flag, sum} = require(‘moduleA’)
webpack入門
Vue Cli詳解
安裝
npm install -g @vue/cli
初始化項(xiàng)目
- Vue cli3
vue create projectName
- 兼容Vue cli2
npm install @vue/cli-init -g
vue init webpack projectName
Vue CLI2使用
vue init webpack vuecli2test
輸入上述命令后有以下配置:
- Project name : 項(xiàng)目名稱路星,不能包含大寫
- Project description
- Author: 作者信息,默認(rèn)會從git中讀取
- Vue build : runtime + complier和runtime-only
- Install vue-router : 是否安裝路由
- 其他不重要的
chrome使用v8引擎直接將js代碼轉(zhuǎn)換成二進(jìn)制文件诱桂,所以運(yùn)行速度較快
node環(huán)境可以直接執(zhí)行js文件
node test.js
static文件夾和assets文件夾的區(qū)別洋丐?
都是存放靜態(tài)文件的,assets中的圖片會根據(jù)設(shè)置的limits挥等,將大于的使用hash重命名后放到dist下對應(yīng)文件夾中友绝,小于的轉(zhuǎn)換成base64格式直接顯示。而static中的文件肝劲,webpack不會進(jìn)行處理迁客,會原樣顯示。
runtime+complier和runtime-only的區(qū)別
//runtime+complier
import App from './App'
new Vue({
el: '#app',
template: '<App/>'
})
template-->ast(抽象語法樹)-->render-->virtualDom-->realDom
//runtime-only (性能更高辞槐,代碼更少(少了complier那部分))
new Vue({
el: '#app',
render: h=>h(App)
})
h實(shí)際是createElement函數(shù)
普通用法: createElement(標(biāo)簽, {屬性}, [內(nèi)容])
createElement('h2', {class: 'box', ['hello world']})
也可以直接傳入組件: createElement(App)
render-->virtualDom-->realDom
runtime-only模式不包含template掷漱,那么app中的template是如何處理的?使用vue-template-complier將template編譯成render函數(shù)后才使用
Vue Cli3
vue-cli3和vue-cli2的區(qū)別
- vue-cli3是基于webpack4打造榄檬,vue-cli2還是webpack3
- vue-cli3的設(shè)計(jì)原則是“0配置”卜范,移除了配置文件目錄下的build和config等目錄
- vue-cli3提供vue ui命令,提供了可視化配置鹿榜,更加人性化
- 移除了static文件夾海雪,新增了public文件夾,并且index.html移動到public中
Vue Cli3修改配置的方法
vue ui啟動一個(gè)本地服務(wù),在界面上修改
node_modules下面的@vue/webpack.config.js
-
在當(dāng)前項(xiàng)目下創(chuàng)建一個(gè)文件舱殿,vue.config.js
module.exports = { }