Vue安裝
安裝腳手架寇钉,使用全局安裝就可以
npm install -g @vue/cli
安裝完使用這個(gè)命令查看vue cli的版本
vue -V
初始化一個(gè)Vue項(xiàng)目
vue create lk-demo
然后會(huì)進(jìn)入一大堆的選項(xiàng)
1. Manually select features
2. 空格選擇咧织,A全選,手動(dòng)配置
運(yùn)行項(xiàng)目
npm run serve
將項(xiàng)目打包到dist目錄
npm run build
如果只有配置文件臼朗,那么需要手動(dòng)安裝依賴才能運(yùn)行
npm install
Vue指令
雙括號(hào)表達(dá)式{{intro}}
- 可以直接展示出data中的數(shù)據(jù)
- 還可以對(duì)數(shù)據(jù)進(jìn)行一些字符串的操作:
{{intro.toUpperCase()}}
- 注意雙括號(hào)表達(dá)式是寫(xiě)在兩個(gè)標(biāo)簽中間的,這意味著你可以將它與其它字符進(jìn)行拼接
v-text
- v-text是一個(gè)屬性,如果倪同時(shí)還在兩個(gè)標(biāo)簽中間寫(xiě)上其它字符视哑,其它字符并不會(huì)顯示出來(lái)
- 僅僅是純文本绣否,data中的數(shù)據(jù)會(huì)被完完整整地展示出來(lái)
v-html
- data中的數(shù)據(jù)會(huì)以html的形式展示出來(lái)
v-bind
這些指令都不需要在雙引號(hào)內(nèi)部寫(xiě)雙括號(hào)表達(dá)式
v-bind:href
- 作用就是給HTML標(biāo)簽綁定某個(gè)屬性,該屬性在data里面:
v-bind:href="site"
- 可以簡(jiǎn)寫(xiě)為:
:href="site"
v-bind:class
<div :class="oneClass">樣式類可以是字符串</div>
<div :class="{classOne: true, classTwo: true}">樣式類可以是對(duì)象</div>
<div :class="['classOne', 'classTwo']">樣式類可以是數(shù)組</div>
<div :class="[oneClass, twoClass]">樣式類可以是數(shù)組</div>
- 如果是字符串挡毅,那么引號(hào)里的是data里的屬性
- 如果是對(duì)象蒜撮,對(duì)象里的就是樣式表里的選擇器
- 如果是數(shù)組,數(shù)組里的字符串也是樣式表里的選擇器
- 同樣是數(shù)組跪呈,但是數(shù)組里不是字符串段磨,那就可以寫(xiě)data里的數(shù)據(jù)
v-bind:style
<div
style="width: 300px; height: 200px; margin: 10px auto;"
:style="{backgroundColor: bgColor, fontSize: fSize}">樣式類可以是字符串</div>
- v-bind:style的方式同樣可以給元素綁定樣式,只不過(guò)是內(nèi)聯(lián)樣式耗绿。
- 注意屬性名采用駝峰命名法薇溃,屬性實(shí)在data中定義的。
v-on:click
- 就是給該元素綁定某個(gè)methods中的事件
- 可以不傳遞參數(shù):
v-on:click="study"
缭乘,也可以傳遞參數(shù)@click="study('小撩')"
- 當(dāng)然沐序,你應(yīng)該也看出來(lái)了,它可以簡(jiǎn)寫(xiě):
@click="study"
- 傳遞參數(shù)之后堕绩,用什么來(lái)接收參數(shù)呢策幼?首先方法里面的形參一定是有的,方法里面奴紧,可以用
${name}
特姐,來(lái)接收參數(shù)。 -
<button @click="flag = !flag">切換</button>
黍氮,@click不僅可以用來(lái)綁定函數(shù)唐含,還可以直接把方法寫(xiě)在里面。
study(name){
alert(`${name},祝你學(xué)有所成沫浆!`);
}
v-model
- 該指令的作用就是將它所綁定的數(shù)據(jù)和data中的數(shù)據(jù)實(shí)現(xiàn)一個(gè)雙向綁定捷枯,實(shí)時(shí)互通。
- 用法就是:
v-model="msg"
v-if
<div v-if="flag">今晚要上課专执!</div>
<div v-else>今晚不上課淮捆!</div>
- v-if還有與之配套的v-else
- v-if并不是通過(guò)設(shè)置css屬性display完成隱藏的
v-show
<div v-show="flag">今晚講Vue!</div>
<div v-show="!flag">今晚不講Vue本股!</div>
- 是通過(guò)設(shè)置
display: none;
來(lái)隱藏元素的攀痊。因此如果需要頻繁進(jìn)行顯示、隱藏操作的話拄显,它是比v-if更好的選擇苟径。
v-for
遍歷數(shù)組
<ul>
<li v-for="(person, index) in persons" :key="personsKeys[index]">
ID: {{personsKeys[index]}} ---- {{index}} ) 姓名:{{person.name}}, 年齡:{{person.age}}, 性別:{{person.sex}}
</li>
</ul>
- v-for應(yīng)該用在li標(biāo)簽而不是ul標(biāo)簽上
- 注意括號(hào)里的第一個(gè)參數(shù)就相當(dāng)于數(shù)組里的每一項(xiàng),使用它就可以用對(duì)象的付出調(diào)用其各個(gè)數(shù)據(jù)
注意:這里還涉及到shortid
的使用
安裝
shortid
:npm i shortid --save
在該組件中導(dǎo)入:
import shortId from 'shortid'
在data中要有
personsKeys
這個(gè)數(shù)據(jù)躬审,它是一個(gè)空的數(shù)組注意要添加一個(gè)mounted掛載點(diǎn)棘街,調(diào)用shortid自動(dòng)產(chǎn)生一個(gè)隨機(jī)數(shù)作為id
mounted() {
this.personsKeys = this.persons.map(v=>shortId.generate())
}
- 然后就可以如上面代碼部分那樣使用了
- v-for可能需要使用
:key
這個(gè)屬性蟆盐,不然的話可能在控制臺(tái)會(huì)報(bào)警告
遍歷對(duì)象
<ul>
<li v-for="(item, key) in persons[0]">
{{key}} --- {{item}}
</li>
</ul>
- key就是對(duì)象的key
- item相當(dāng)于對(duì)象的value
其它指令
v-pre
<p v-pre>{{intro}}</p>
- 貌似加了這個(gè)屬性之后,雙括號(hào)表達(dá)式就不會(huì)解析了蹬碧,而會(huì)被當(dāng)作純文本展示在頁(yè)面上。
- 它并不需要參數(shù)
v-cloak
<p v-cloak>{{message}}</p>
- 當(dāng)某些情況下炒刁,Vue加載有點(diǎn)慢恩沽,這個(gè)時(shí)候可能就會(huì)以源碼的形式展示出來(lái),比如這里的雙括號(hào)表達(dá)式翔始,這個(gè)時(shí)候使用v-cloak就可以避免這個(gè)閃爍問(wèn)題罗心。
v-once
<p v-once>{{name}}</p>
- 它會(huì)使得雙括號(hào)表達(dá)式僅解析一次,之后即便通過(guò)v-model改變了data中的數(shù)據(jù)也不會(huì)更新
ref的使用
<p ref="fish">我是一只魚(yú)</p>
- 這東西并不是一個(gè)指令城瞎,好像是引用什么的吧渤闷。官方的解釋是:ref 被用來(lái)給元素或子組件注冊(cè)引用信息。引用信息將會(huì)注冊(cè)在父組件的 $refs 對(duì)象上脖镀。如果在普通的 DOM 元素上使用飒箭,引用指向的就是 DOM 元素;如果用在子組件上蜒灰,引用就指向組件弦蹂。
- 其實(shí)可以把它看做id屬性,通過(guò)它獲取到該元素然后就可以進(jìn)行某些操作强窖。
- 如果想要輸出它里面的內(nèi)容凸椿,可以采用這種方式。注意這里的innerHTML只會(huì)輸出<p>標(biāo)簽中間部分的html內(nèi)容
console.log(this.$refs.fish.innerHTML);
自定義全局和局部指令
自定義全局指令
Vue.directive('upper-word', (el, binding)=>{
console.log(el, binding);
el.textContent = binding.value.toUpperCase();
});
- 全局指令需要寫(xiě)在main.js中
- Vue的指令都需要在前面加一個(gè)
v-
自定義局部指令
directives: {
'lower-word'(el, binding){
console.log(el, binding);
el.textContent = binding.value.toLowerCase();
}
}
- 局部指令的定義使用的是
directives
這個(gè)鉤子選項(xiàng) - 注意它和全局指令的定義有一些細(xì)微的不同翅溺。
計(jì)算屬性
- 計(jì)算屬性和data中的數(shù)據(jù)一樣脑漫,都可以使用v-model來(lái)進(jìn)行綁定
- 計(jì)算屬性都有
set()
和get()
方法,get()
用于對(duì)data中的數(shù)據(jù)進(jìn)行計(jì)算咙崎,set()
用于將從它獲取到的數(shù)據(jù)賦給data中的數(shù)據(jù)
fullNameTwo: {
get(){
// console.log(`調(diào)用了fullNameTwo的getter方法`);
return this.firstName + '·' + this.lastName;
},
set(value){
// console.log(`調(diào)用了fullNameTwo的setter方法,值:${value}`);
// 1.更新firstName和lastName
let names = value.split('·');
console.log(names);
this.firstName = names[0];
this.lastName = names[1];
}
}
數(shù)據(jù)監(jiān)聽(tīng)watch
// 配置watch
watch: {
// 監(jiān)聽(tīng)firstName
firstName(value){
console.log(`watch監(jiān)視到firstName發(fā)生改變:${value}`);
// 更新fullNameThree
this.fullNameThree = value + '·' + this.lastName;
},
// 監(jiān)聽(tīng)lastName
lastName(value){
console.log(`watch監(jiān)視到lastName發(fā)生改變:${value}`);
// 更新fullNameThree
this.fullNameThree = this.firstName + '·' + value;
}
}
- watch和data优幸、computed是同一級(jí)屬性,可以用來(lái)對(duì)data中的數(shù)據(jù)進(jìn)行監(jiān)聽(tīng)褪猛。
- watch里面每個(gè)函數(shù)的名字與data里的屬性相同劈伴,當(dāng)該屬性被改變,就會(huì)自動(dòng)調(diào)用該方法握爷。
- 該方法可以內(nèi)部同樣可以中data中的數(shù)據(jù)進(jìn)行運(yùn)算跛璧。
事件處理
事件對(duì)象
<button @click="clickBtn('撩課', $event)">點(diǎn)我</button>
- 可以在觸發(fā)事件的同時(shí)將參數(shù)和事件對(duì)象都傳遞過(guò)去,該事件對(duì)象里面有很多很多與時(shí)間相關(guān)的屬性
事件修飾符@click.prevent
<a @click.prevent="aClick">撩課</a>
- 它的存在是可以阻止該元素默認(rèn)的行為的新啼。
- 比如上面這個(gè)是個(gè)超鏈接追城,但是現(xiàn)在點(diǎn)擊之后并不會(huì)跳轉(zhuǎn),而是執(zhí)行aClick()方法
- 如果是form燥撞,也會(huì)阻止掉自動(dòng)提交的方法座柱。
事件修飾符@click.stop
<div style="width: 100px; height: 100px; background-color:red;" @click="divClick">
<button @click.stop="btnClick">點(diǎn)我</button>
</div>
- 該修飾符是用在子元素標(biāo)簽上的迷帜,可以用來(lái)阻止事件冒泡。也就是說(shuō)色洞,使用之后戏锹,點(diǎn)擊子元素的標(biāo)簽并不會(huì)觸發(fā)父元素上的事件。
按鍵修飾符
<input type="text" @keyup.enter="dealKey">
dealKey(event){
console.log(event);
console.log(event['keyCode']);
}
- 使用@keyup可以在后面跟上很多種按鍵火诸,也就是當(dāng)按下然后松開(kāi)之后就會(huì)執(zhí)行該事件锦针。
- 另外在觸發(fā)事件的對(duì)象里可以通過(guò)
event['keyCode']
獲取按鍵的ASCII碼
過(guò)濾器
全局過(guò)濾器
Vue.filter('wholeMoneyFormat', (value)=>{
return '¥' + Number(value).toFixed(4);
});
<p>{{money | wholeMoneyFormat}}</p>
- 全局過(guò)濾器需要寫(xiě)在main.js中,如上面的代碼所示
- 上面的過(guò)濾器的意思是:將傳過(guò)來(lái)的參數(shù)轉(zhuǎn)成數(shù)字置蜀,并且保留四位小數(shù)奈搜,然后在前面加上一個(gè)人民幣的符號(hào)并返回。
- 使用的時(shí)候需要使用雙括號(hào)表達(dá)式盯荤,第一個(gè)是需要過(guò)濾的參數(shù)馋吗,第二過(guò)濾器的名字,中間用豎線隔開(kāi)秋秤。
局部過(guò)濾器
filters: {
moneyFormat(value){
return '¥' + Number(value).toFixed(2);
},
timeFormat(value, format='YYYY-MM-DD HH:mm:ss'){
return moment(value).format(format);
}
}
- 局部過(guò)濾器的定義如上面的代碼所示宏粤。使用方法和全局過(guò)濾器是完全一樣的
- 第一個(gè)金錢過(guò)濾器,是將傳遞過(guò)來(lái)的參數(shù)轉(zhuǎn)成保留兩位小數(shù)的數(shù)字灼卢,并且在前面加上一個(gè)人民幣符號(hào)商架。
- 第二個(gè)時(shí)間過(guò)濾器需要使用moment插件,將value中的事件轉(zhuǎn)成format中的時(shí)間格式芥玉。當(dāng)然也可以在調(diào)用的時(shí)候手動(dòng)修改過(guò)濾的時(shí)間格式蛇摸。
<p>{{time | timeFormat('YYYY-MM-DD')}}</p>
Vue過(guò)渡和動(dòng)畫(huà)
只使用類
<button @click="show = !show">切換</button>
<transition name="fade">
<div class="box" v-if="show">撩課學(xué)院</div>
</transition>
- 在Vue中使用動(dòng)畫(huà),需要使用transition標(biāo)簽灿巧,該標(biāo)簽必須具備一個(gè)name屬性
- 我們可以通過(guò)設(shè)置一個(gè)v-if來(lái)切換該元素出現(xiàn)和消失時(shí)的動(dòng)畫(huà)
- 然后在樣式表中寫(xiě)好終點(diǎn)的樣式以及進(jìn)行中的樣式赶袄。選擇器的名字需要使用到上面提到的name屬性,比如:
.fade-enter
,.fade-leave-to
抠藕,.fade-enter-active
,.fade-leave-active
- 下面這個(gè)就是一個(gè)CSS的例子
.fade-enter, .fade-leave-to{
opacity: 0;
transform: translateX(200px) scale(3);
}
.fade-enter-active, .fade-leave-active{
transition: all 2s ease-in-out;
}
使用@keyframes
- 注意:如果圖片采用:src這種方式導(dǎo)入的話饿肺,需要先導(dǎo)入這樣圖片
import pic from '@/assets/img_02.jpg'
,然后將其作為data中的一個(gè)數(shù)據(jù) - 兩個(gè)CSS類盾似,第一個(gè)表示進(jìn)入時(shí)候的動(dòng)畫(huà)以及持續(xù)時(shí)間敬辣。第二個(gè)表示消失時(shí)候的動(dòng)畫(huà)以及持續(xù)時(shí)間,并且表明和第一個(gè)動(dòng)畫(huà)是相反的零院。
- 詳細(xì)代碼如下
<button @click="flag = !flag">切換</button>
<p></p>
<transition name="bounce">
<img v-if="flag" :src="pic" alt="">
</transition>
.bounce-enter-active {
animation: bounce 1s;
}
.bounce-leave-active {
animation: bounce 1s reverse;
}
@keyframes bounce {
0% {
transform: scale(0);
}
25% {
transform: scale(0.2);
}
50% {
transform: scale(0.4);
}
75% {
transform: scale(0.6);
}
100% {
transform: scale(1);
}
}
導(dǎo)入外部的動(dòng)畫(huà)CSS庫(kù)
<button @click="flag = !flag">切換</button>
<p></p>
<transition
enter-active-class="animated rollIn"
leave-active-class="animated rollOut"
:duration="{ enter: 1000, leave: 500 }"
>
<img v-if="flag" :src="pic" alt="">
</transition>
- 該動(dòng)畫(huà)庫(kù)的使用情況如上面的代碼
- 安裝animate.css:
npm i animate.css --save
- 然后導(dǎo)入
animate.css
:import animate from 'animate.css'
- transition中的三個(gè)屬性分別表示進(jìn)入時(shí)候的動(dòng)畫(huà)溉跃、消失時(shí)候的動(dòng)畫(huà),以及進(jìn)入和消失的持續(xù)時(shí)間告抄。
生命周期
- Vue的生命周期按順序有:
beforeCreate
撰茎、created
、beforeMount
打洼、mounted
龄糊、beforeUpdate
逆粹、updated
炫惩、beforeDestroy
、destroyed
- 一般來(lái)說(shuō)只要該組件啟用他嚷,前面四個(gè)生命周期都會(huì)很快依次調(diào)用蹋绽。
- 然后蟋字,每次修改data中的數(shù)據(jù)稿蹲,都會(huì)調(diào)用
beforeUpdate
、updated
兩個(gè)方法 - 最后苛聘,如果想要進(jìn)入銷毀的生命周期需要主動(dòng)觸發(fā)下面代碼的這個(gè)方法
- 另外涂炎,定時(shí)器如果在生命周期里设哗,注意它是異步的,即便已經(jīng)銷毀可能定時(shí)器仍然在工作网梢。這個(gè)時(shí)候最好在銷毀的生命周期里設(shè)置一個(gè)清除定時(shí)器的方法。
destory(){
this.$destroy();
}
組件通信
子組件通知父組件战虏,我觸發(fā)了某個(gè)方法
父組件
- App.vue在組件上面需要綁定事件
- 在methods中寫(xiě)事件
<CustomEvents @btnClick="deleteP"/>
deleteP(args){
console.log(args);
this.$refs.word.remove();
}
子組件
- 子組件同樣需要給某個(gè)元素綁定事件
- 但不是自己處理事件拣宰,而是告訴父元素,自己觸發(fā)了哪個(gè)事件烦感,參數(shù)是什么
btnClick(){
// 告訴父組件巡社,我點(diǎn)擊了按鈕
this.$emit('btnClick', {name: '哈哈哈', sex:'男'});
// TODO
}
父組件向子組件傳遞數(shù)據(jù)和方法:props
<PropsComponent :age=25 :person="p" :log-person="logPerson" />
props: {
name: String,
age: Number,
person: Object,
logPerson: Function
}
*/
props: {
name: {type: String, required: true, default: '撩課'},
age: {type: Number, required: true, default: 20},
person: Object,
logPerson: Function
}
- 父組件通過(guò)在組件上寫(xiě)
:age
的形式,向子組件傳遞數(shù)據(jù)和方法手趣。這些數(shù)據(jù)和方法都是在父組件中已經(jīng)定義好的 - 子組件需要通過(guò)props這個(gè)鉤子選項(xiàng)接收父組件傳遞過(guò)來(lái)的數(shù)據(jù)和方法晌该,有上面兩種形式
- 然后子組件就可以像使用自己的數(shù)據(jù)和方法一樣使用父組件的數(shù)據(jù)和方法
自定義事件
- 由子組件發(fā)送給父組件,函數(shù)名稱绿渣,函數(shù)參數(shù)
this.$emit('addTodo', todo);
- 父組件需要監(jiān)聽(tīng)這個(gè)組件:
<Header ref="header"/>
- 然后給父組件綁定自定義事件的監(jiān)聽(tīng):
this.$refs.header.$on('addTodo', this.addTodo);
注意這是寫(xiě)在mounted
這個(gè)鉤子選項(xiàng)里的朝群;然后不用寫(xiě)()來(lái)接參數(shù),這種寫(xiě)法就會(huì)自動(dòng)把todo參數(shù)傳遞過(guò)來(lái)
發(fā)布訂閱模式
- 安裝pubsub插件:
npm install --save pubsub-js
- 在App.vue和item中引入pubsub-js:
import PubSub from 'pubsub-js'
中符,反正哪里需要發(fā)布潜圃、訂閱就需要引入 - 子組件發(fā)布消息:
PubSub.publish('delTodo', this.index)
- 父組件接收消息。代碼如下舟茶。注意谭期,同樣寫(xiě)在mounted這個(gè)鉤子選項(xiàng)下堵第,token就是子組件傳遞過(guò)來(lái)的參數(shù)
PubSub.subscribe('delTodo', (msg, token)=>{
// console.log(msg, token);
this.delTodo(token);
});
插槽
<label>
<slot name="isCheck"></slot>
</label>
<span>
<slot name="finish"></slot>
</span>
<slot name="delete"></slot>
<Footer>
<input slot="isCheck" type="checkbox" v-model="isCheck"/>
<span slot="finish">已完成{{finishedCount}}件 / 總計(jì){{todos.length}}件</span>
<button slot="delete" class="btn btn-warning" @click="delFinishedTodos">清除已完成任務(wù)</button>
</Footer>
- footer中不用自己寫(xiě)代碼了,直接把插槽留出來(lái)就行隧出。使用的是<slot>標(biāo)簽踏志,注意必須有name屬性。
- 父組件里面直接往子組件里面插入
- 這樣就可以直接調(diào)用父組件里面的方法和計(jì)算屬性了
Vuex
- 安裝:
vue add vuex
Vue router
Vue-router的基本使用
- 安裝:npm install vue-router --save
- 新建router.js文件
- 在main.js中引入胀瞪,并且放入Vue的實(shí)例中
- 新建view頁(yè)面针余,并且在App.vue中配置路由導(dǎo)航和路由出口
router.js
import Vue from 'vue'
import Router from 'vue-router'
// 引入頁(yè)面
import Home from './views/Home'
import About from './views/About'
Vue.use(Router);
export default new Router({
// history模式就是沒(méi)有#
// mode: 'history',
routes: [
{ path: '/', redirect: '/home' },
// 下面這個(gè)就是重定向到一個(gè)命名路由,name就是路由的名字
// { path: '/', redirect: {name: 'about'} },
// 下面這個(gè)是使用一個(gè)方法重定向到目標(biāo)路由
// { path: '/', redirect: to => { return '/home'}},
// 這里name屬性僅僅只是這個(gè)路由的名字凄诞,暫時(shí)沒(méi)有用處
{path: '/home', name: 'home', component: Home},
{path: '/about', name: 'about', component: About},
]
})
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App),
}).$mount('#app');
在App.vue中配置路由導(dǎo)航和路由出口
<!--設(shè)置路由導(dǎo)航-->
<div id="nav">
<router-link to="/home">首頁(yè)</router-link>
<router-link to="/about">關(guān)于</router-link>
</div>
<!--設(shè)置路由出口-->
<router-view></router-view>
路由history和hash模式
獲取路由參數(shù)
import Vue from 'vue'
import Router from 'vue-router'
// 引入頁(yè)面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'
Vue.use(Router);
/*
let func = ({params, query})=>{
return {
name: params.name,
sex: params.sex,
height: query.height,
dog: query.dog,
}
};
*/
let func = (route)=>{
return {
name: route.params.name,
sex: route.params.sex,
height: route.query.height,
dog: route.query.dog,
}
};
export default new Router({
routes: [
{ path: '/', redirect: '/home' },
{path: '/home', name: 'home', component: Home},
{path: '/about', name: 'about', component: About},
// {path: '/mine/:name/:sex', name: 'mine', component: Mine}
// {path: '/mine', name: 'mine', component: Mine, props: {name: '小撩'}}
// {path: '/mine/:name/:sex', name: 'mine', component: Mine, props: true}
{path: '/mine/:name/:sex', name: 'mine', component: Mine, props: func}
]
})
Mine.vue
<template>
<div id="mine">
<h2>個(gè)人中心</h2>
<p>------------------------------------------</p>
<h2>根據(jù)路由對(duì)象獲取的路徑參數(shù)</h2>
<p>姓名:{{$route.params.name}}</p>
<p>性別:{{$route.params.sex}}</p>
<p>身高:{{$route.query.height}}</p>
<p>小狗:{{$route.query.dog}}</p>
<h2>根據(jù)屬性對(duì)象獲取的路徑參數(shù)</h2>
<p>姓名:{{name}}</p>
<p>性別:{{sex}}</p>
<p>身高:{{height}}</p>
<p>小狗:{{dog}}</p>
</div>
</template>
<script>
export default {
name: "Mine",
props: ['name', 'sex', 'height', 'dog'],
created() {
console.log(this.$route);
/*
console.log(this.$route);
console.log(this.$route.path);
console.log(this.$route.params);
console.log(this.$route.query);
*/
// console.log(this.$router);
}
}
</script>
<style scoped>
#mine{
width: 300px;
height: 500px;
background-color: orange;
margin: 0 auto;
}
h2{
color: green;
}
</style>
- 關(guān)于獲取路由參數(shù)的代碼在上邊
- 所謂的獲取路由參數(shù)其實(shí)就是指圆雁,數(shù)據(jù)是在鏈接上的,我們需要通過(guò)某種方式獲取到這些數(shù)據(jù)
- 通過(guò)路由傳遞參數(shù)主要有幾種方式:
-
{path: '/mine/:name/:sex', name: 'mine', component: Mine}
帆谍,通過(guò)在路由上寫(xiě)冒號(hào) -
{path: '/mine', name: 'mine', component: Mine, props: {name: '小撩'}}
伪朽,通過(guò)props獲取數(shù)據(jù),注意需要在該組件內(nèi)部寫(xiě)出props這個(gè)鉤子選項(xiàng)汛蝙,并且內(nèi)容為這些數(shù)據(jù)的變量名 -
{path: '/mine/:name/:sex', name: 'mine', component: Mine, props: true}
烈涮,通過(guò)以上兩種方式獲取數(shù)據(jù) -
{path: '/mine/:name/:sex', name: 'mine', component: Mine, props: func}
,通過(guò)地址和方法傳遞數(shù)據(jù)
嵌套路由
import Vue from 'vue'
import Router from 'vue-router'
// 一級(jí)界面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'
// 二級(jí)界面
import News from './views/News'
import Shop from './views/Shop'
Vue.use(Router);
export default new Router({
routes: [
{ path: '/', redirect: '/home' },
{
path: '/home',
name: 'home',
component: Home,
children: [
{ path: '/home', redirect: '/home/news' },
{path: 'news', name: 'news', component: News},
{path: 'shop', name: 'shop', component: Shop},
]
},
{path: '/about', name: 'about', component: About},
{path: '/mine', name: 'mine', component: Mine}
]
})
- 所謂的嵌套路由就是斜杠后面還有斜杠
- 嵌套路由的配置其它文件并沒(méi)有什么不同窖剑,主要還是在router.js上的不同
- 嵌套路由的配置主要小心:子路由不需要在前面寫(xiě)/
全局路由前置和后置守衛(wèi)
import Vue from 'vue'
import Router from 'vue-router'
// 一級(jí)界面
import Login from './views/Login'
import DashBoard from './views/DashBoard'
// 二級(jí)界面
import Home from './views/Home'
// import About from './views/About'
import Mine from './views/Mine'
const About = ()=> import('./views/About');
Vue.use(Router);
const router = new Router({
routes: [
{ path: '/', redirect: '/dashboard' },
{
path: '/dashboard',
name: 'dashboard',
component: DashBoard,
children: [
{ path: '/dashboard', redirect: '/dashboard/home' },
{path: 'home', name: 'home', component: Home,},
{path: 'about', name: 'about', component: About},
{path: 'mine', name: 'mine', component: Mine}
],
},
{path: '/login', name: 'login', component: Login}
]
});
// 全局路由前置守衛(wèi)
router.beforeEach((to, from, next)=>{
// console.log(to, from);
if(to.path !== '/login'){ // 驗(yàn)證是否登錄
if(window.isLogin){ // 已經(jīng)登錄
next();
}else { // 沒(méi)有登錄
// 將你要去的地址也傳到登錄頁(yè)去坚洽,這樣當(dāng)你登錄成功之后可以立即重定向到該頁(yè)
// next('/login?redirect='+ to.path);
// next('/login?redirect=/dashboard/mine');
next('/login');
}
}else { // 不需要驗(yàn)證
next();
}
// 放行
next();
});
// 全局路由后置守衛(wèi)
router.afterEach((to, from) => {
// console.log('來(lái)了!');
});
export default router;
- 主要通過(guò)前置守衛(wèi)來(lái)控制什么情況下用戶可以進(jìn)入頁(yè)面
- 如果用戶進(jìn)的是登錄頁(yè)西土,無(wú)需檢查直接放行
- 如果用戶進(jìn)的是其它頁(yè)讶舰,檢查是否登錄,如果沒(méi)有登錄前往登錄頁(yè)需了,如果已經(jīng)登錄放行
- 其它情況一律放行
mine.vue
export default {
name: "Mine",
beforeRouteEnter(to, from, next){
console.log('進(jìn)入之前調(diào)用');
next();
},
beforeRouteUpdate(to, from, next){
console.log('路由的參數(shù)變了');
next();
},
beforeRouteLeave(to, from, next){
console.log('路由離開(kāi)前調(diào)用');
next();
}
}
這里主要設(shè)置了幾個(gè)生命周期的鉤子選項(xiàng)跳昼,在進(jìn)入這個(gè)組件之前庐舟、路由參數(shù)改變、以及路由離開(kāi)的時(shí)候都會(huì)分別調(diào)用這里的方法
login.vue
<template>
<div>
<h2>登錄界面</h2>
<button @click="login">登錄</button>
</div>
</template>
<script>
export default {
name: "Login",
methods: {
login(){
// 1. 登錄成功
window.isLogin = true;
// 2. 獲取回調(diào)地址
const redirect = this.$route.query.redirect;
if(redirect){ // 有回調(diào)地址
this.$router.push(redirect);
}else { // 沒(méi)有回調(diào)地址
// 去首頁(yè)
this.$router.replace('/');
}
}
}
}
</script>
<style scoped>
</style>
- 登錄的這個(gè)頁(yè)面主要負(fù)責(zé)處理登錄相關(guān)的事務(wù)
- 當(dāng)用戶點(diǎn)擊登錄按鈕之后挪略,首先將全局的isLogin設(shè)置為true
- 獲取用戶的回調(diào)地址杠娱,如果有回調(diào)地址則直接前往谱煤;如果沒(méi)有則前往主頁(yè)
數(shù)據(jù)本地化
- 手寫(xiě)一個(gè)工具類
- 在app.vue中導(dǎo)入該工具類
- data中的數(shù)據(jù)需要從localStorage中讀取,當(dāng)todos數(shù)據(jù)發(fā)生任何改變就要把該數(shù)據(jù)存儲(chǔ)到localStorage
工具類
const LK_TODO = 'lk_todo';
export default {
readTodos(){
return JSON.parse(localStorage.getItem(LK_TODO) || '[]');
},
saveTodos(todos){
console.log(todos);
localStorage.setItem(LK_TODO, JSON.stringify(todos));
}
}
- 使用localStorage無(wú)論是讀還是取室叉,都需要傳遞一個(gè)key,注意這里僅僅一個(gè)數(shù)組茧痕,所以使用了一個(gè)字符串常量作為key
- 第一個(gè)讀取數(shù)據(jù)的方法內(nèi)部有
|| '[]'
是為了在任何情況下都能夠讀到數(shù)據(jù),哪怕是一個(gè)空的數(shù)組
讀數(shù)據(jù)
todos: localStorageUtil.readTodos()
取數(shù)據(jù)
watch: {
// 深度監(jiān)視
todos: {
handler: localStorageUtil.saveTodos,
deep: true, // 深度監(jiān)視
// immediate: true
}
}
- 取數(shù)據(jù)需要深度監(jiān)視曼氛,因?yàn)閿?shù)組里面還有對(duì)象令野,只有深度監(jiān)視能夠監(jiān)聽(tīng)數(shù)組里面對(duì)象屬性的改變。
- immediate如果為true气破,就是當(dāng)初始化的時(shí)候就立即執(zhí)行handler方法,否則就是當(dāng)todos發(fā)生改變才會(huì)執(zhí)行handler方法狗超。
UI框架
elementUI
- element文檔:https://element.eleme.cn/#/zh-CN/component/layout
- 安裝:
npm i element-ui -S
- 給Vue添加UI庫(kù):
vue add element
- 選項(xiàng):Fully import朴下、N苦蒿、CN
-
vue ui
:使用可視化面板管理項(xiàng)目(一般不會(huì)用的)
做完以上幾步就會(huì)發(fā)現(xiàn),自動(dòng)集成了plugins/element.js
团滥,并且自動(dòng)在main.js
中導(dǎo)入了报强。然后就可以直接在app.vue中使用了。
- 復(fù)制HTML代碼到模板里面
- 復(fù)制script代碼data部分到app.vue里力惯,注意這里和vue的代碼結(jié)構(gòu)是完全一樣的召嘶。
VantUI
- 文檔:https://youzan.github.io/vant/#/zh-CN/
- 安裝:
npm i vant -S
- 配置按需加載,引入babel:
npm i babel-plugin-import -D
- 配置babel.config.js甲喝,可以從文檔里復(fù)制粘貼
- 在main.js從引入需要的組件铛只,或者單獨(dú)做一個(gè)js文件糠溜,然后通過(guò)import來(lái)引入
配置babel.config.js
module.exports = {
presets: [
'@vue/app'
],
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
};
在main.js中引入需要的組件
import { Button } from 'vant';
Vue.use(Button);
import { Cell, CellGroup } from 'vant';
Vue.use(Cell).use(CellGroup);
import { DatetimePicker } from 'vant';
Vue.use(DatetimePicker);
插件的安裝和使用
shortid
<ul>
<li v-for="(person, index) in persons" :key="personsKeys[index]">
ID: {{personsKeys[index]}} ---- {{index}} ) 姓名:{{person.name}}, 年齡:{{person.age}}, 性別:{{person.sex}}
</li>
</ul>
- 安裝
shortid
:npm i shortid --save
- 在該組件中導(dǎo)入:
import shortId from 'shortid'
- 在data中要有
personsKeys
這個(gè)數(shù)據(jù)诵冒,它是一個(gè)空的數(shù)組 - 注意要添加一個(gè)mounted掛載點(diǎn)谊惭,調(diào)用shortid自動(dòng)產(chǎn)生一個(gè)隨機(jī)數(shù)作為id
mounted() {
this.personsKeys = this.persons.map(v=>shortId.generate())
}
- 然后就可以如上面代碼部分那樣使用了
- v-for可能需要使用
:key
這個(gè)屬性,不然的話可能在控制臺(tái)會(huì)報(bào)警告
moment
- 安裝:
npm i moment --save
- 使用:注意任何插件的使用圈盔,都需要在該組件內(nèi)部首先導(dǎo)入
import moment from 'moment'
。然后就可以像調(diào)用函數(shù)一樣使用該插件了
案例匯總
v-for排序小案例
- 數(shù)據(jù)來(lái)源于data中已經(jīng)定義好的
- v-for的使用和之前遍歷數(shù)組的時(shí)候是一樣的铁蹈,同樣用到了shortid众眨,但是并沒(méi)有把shortid展示在頁(yè)面上,而是用索引加1的方式
- v-for里的in沿腰,是已經(jīng)排序好的數(shù)組狈定,該數(shù)組是使用計(jì)算屬性而得到的
- 排序分為默認(rèn),按年齡升序措嵌、降序芦缰,是通過(guò)向計(jì)算屬性里傳遞不同參數(shù)而區(qū)別開(kāi)的。
- 排序的代碼如下浪规。注意需要先過(guò)濾以下數(shù)組,然后根據(jù)條件進(jìn)行排序
computed: {
filterPersons() {
// 1. 獲取數(shù)據(jù)
let {searchName, persons, orderType} = this;
// 2. 取出數(shù)組中的數(shù)據(jù)
let arr = [...persons];
// 3. 過(guò)濾數(shù)組
if (searchName.trim()) {
arr = persons.filter(p => p.name.indexOf(searchName) !== -1);
}
// 4. 排序
if (orderType) {
arr.sort((p1, p2) => {
if (orderType === 1) { // 降序
return p2.age - p1.age
} else { // 升序
return p1.age - p2.age
}
});
}
return arr;
}
},
表單添加刪除小案例
- data里有有已經(jīng)存在的數(shù)據(jù)和一個(gè)新的空對(duì)象對(duì)象罗丰,這個(gè)空對(duì)象可以設(shè)定一些默認(rèn)值
- 每個(gè)input標(biāo)簽都會(huì)設(shè)置v-model萌抵,分別和空對(duì)象里的各個(gè)屬性綁定起來(lái)
- 添加數(shù)據(jù)的時(shí)候:首先使用解構(gòu)賦值從該對(duì)象中獲取輸入框的數(shù)據(jù);然后對(duì)數(shù)據(jù)進(jìn)行驗(yàn)證霎桅,比如不能為空讨永;插入數(shù)據(jù)直接使用數(shù)組的unshift方法就可以;最后記得要清空這個(gè)空對(duì)象卿闹,讓其恢復(fù)默認(rèn)值
- 點(diǎn)擊刪除按鈕的時(shí)候:直接調(diào)用splice方法就可以,第一個(gè)參數(shù)是索引著角,第二個(gè)參數(shù)是從該索引的位置刪除幾個(gè)元素
todoList
todoList第一版
Header
- Header的主要任務(wù)是為todoList添加新任務(wù)旋恼,主要方法就是添加todo
- 方法的實(shí)現(xiàn)是在App.vue,然后使用
:addTodo="addTodo"
的方式向子組件傳遞自己的方法产徊。當(dāng)然子組件需要用props來(lái)接收蜀细。 - 子組件只負(fù)責(zé)一個(gè)數(shù)據(jù)title,因?yàn)閯?chuàng)建的時(shí)候任務(wù)不可能完成深滚,所以finished也就是那個(gè)復(fù)選框默認(rèn)設(shè)置為false就行了涣觉。
- 子組件仍需要一些其它的操作:①:判斷用戶輸入的是否是空字符串;②:根據(jù)用戶的輸入拼接一個(gè)todo官册,它主要就是包含title难捌、finished兩個(gè)數(shù)據(jù);③:調(diào)用父組件的添加方法员淫;④:清空title數(shù)據(jù)
List
- List的主要任務(wù)就是:①:當(dāng)鼠標(biāo)移動(dòng)到某一條todo上時(shí)击敌,該todo的背景顏色變?yōu)榛疑⑶绎@示出來(lái)刪除按鈕
- App.vue需要向List傳遞todos數(shù)據(jù)和刪除某一條todo的方法
- List使用props接收todos和刪除方法圣蝎。然后使用v-for對(duì)todos進(jìn)行遍歷,當(dāng)然遍歷的每一個(gè)item就是它的子組件徘公,List需要向item傳遞它的數(shù)據(jù)todo、該todo在todos中的索引坦袍,以及刪除todo的方法
- 子子組件item首先需要接收上面?zhèn)鬟f過(guò)來(lái)的兩個(gè)數(shù)據(jù)一個(gè)方法等太。
- item實(shí)現(xiàn)鼠標(biāo)移入就出現(xiàn)刪除按鈕以及背景顏色的改變是通過(guò)
@mouseenter
、@mouseleave
兩個(gè)觸發(fā)事件的方式澈驼,分別向同一個(gè)事件傳遞true
、false
兩個(gè)不同的參數(shù)挎塌。 - 背景顏色是通過(guò)設(shè)置
:style
使用的是data里面的某個(gè)值内边,這樣就可以使用方法改變data的這個(gè)屬性來(lái)調(diào)整背景顏色 - 按鈕的顯示和隱藏使用的是v-show,同樣是data里的一個(gè)數(shù)據(jù)控制true還是false嘴高,這樣我們?cè)诜椒ɡ锞涂梢栽O(shè)置該屬性為true,來(lái)讓按鈕顯示出來(lái)
- 刪除該todo直接使用父組件里的方法就可以了
Footer
- footer的作用主要是:①:當(dāng)上面的每一條todo都選中的時(shí)候拴驮,它的復(fù)選框也要選中柴信;②:全選;③:點(diǎn)擊刪除所有finished的按鈕潜沦。
- 選中所有todo和刪除已經(jīng)完成的todo都是在app.vue中定義的。然后將這兩個(gè)方法以及todos的數(shù)據(jù)全部傳遞給footer組件
- footer里面很重要的一個(gè)功能就是要知道目前已經(jīng)完成的todo數(shù)量唆鸡,這是通過(guò)計(jì)算屬性實(shí)現(xiàn)的枣察。代碼見(jiàn)下方袄琳。使用的是數(shù)組的reduce這個(gè)方法燃乍,其實(shí)就是一個(gè)遍歷+1計(jì)數(shù)的操作。
- footer里面很重要的一個(gè)功能就是全選逗旁,也就是當(dāng)上面全部選中它也要選中,它如果選中片效,上面也要全部選中英古。這是通過(guò)給該復(fù)選框設(shè)置一個(gè)v-model,并且綁定一個(gè)計(jì)算屬性實(shí)現(xiàn)的膨桥。
- 其中g(shù)et()是處理第一個(gè)的唠叛,判斷條件就是目前已經(jīng)完成的todo數(shù)量和todos的長(zhǎng)度相等,并且長(zhǎng)度不為0.
- 其中set()是處理第二個(gè)的艺沼,它會(huì)將目前該計(jì)算屬性的值true、false作為參數(shù)調(diào)用父組件的全選方法调鲸。父組件的全選方法就會(huì)遍歷整個(gè)todos挽荡,將其中的finished屬性全部設(shè)定為參數(shù)。需要注意的是贯钩,這里有一個(gè)小竅門(mén),就是footer的全選按鈕和v-model綁定,它選中那么set()方法的參數(shù)就是true祸穷。
- 最后刪除所有已經(jīng)完成的todo則很簡(jiǎn)單了,不需要傳遞任何參數(shù)需曾,直接調(diào)用父組件的方法即可。
finishedCount(){
return this.todos.reduce((total, todo)=> total + (todo.finished ? 1 : 0), 0);
},