Vue.js - Day2
品牌管理案例
添加新品牌
刪除品牌
根據(jù)條件篩選品牌
- 1.x 版本中的filterBy指令,在2.x中已經(jīng)被廢除:
<tr v-for="item in list | filterBy searchName in 'name'">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">刪除</a>
</td>
</tr>
- 在2.x版本中手動(dòng)實(shí)現(xiàn)篩選的方式:
- 篩選框綁定到 VM 實(shí)例中的
searchName屬性:
<hr> 輸入篩選名稱:
<input type="text" v-model="searchName">
- 在使用
v-for指令循環(huán)每一行數(shù)據(jù)的時(shí)候,不再直接item in list,而是in一個(gè) 過濾的methods 方法,同時(shí),把過濾條件searchName傳遞進(jìn)去:
<tbody>
<tr v-for="item in search(searchName)">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">刪除</a>
</td>
</tr>
</tbody>
-
search過濾方法中,使用 數(shù)組的filter方法進(jìn)行過濾:
search(name) {
return this.list.filter(x => {
return x.name.indexOf(name) != -1;
});
}
Vue調(diào)試工具vue-devtools的安裝步驟和使用
過濾器
概念:Vue.js 允許你自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個(gè)地方:mustache 插值和 v-bind 表達(dá)式。過濾器應(yīng)該被添加在 JavaScript 表達(dá)式的尾部,由“管道”符指示;
私有過濾器
- HTML元素:
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
- 私有
filters定義方式:
filters: { // 私有局部過濾器,只能在 當(dāng)前 VM 對象所控制的 View 區(qū)域進(jìn)行使用
dataFormat(input, pattern = "") { // 在參數(shù)列表中 通過 pattern="" 來指定形參默認(rèn)值,防止報(bào)錯(cuò)
var dt = new Date(input);
// 獲取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 傳遞進(jìn)來的字符串類型,轉(zhuǎn)為小寫之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否則,就返回 年-月-日 時(shí):分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-$u0z1t8os`;
} else {
// 獲取時(shí)分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-$u0z1t8os ${hh}:${mm}:${ss}`;
}
}
}
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString='') 或 String.prototype.padEnd(maxLength, fillString='')來填充字符串;
全局過濾器
// 定義一個(gè)全局過濾器
Vue.filter('dataFormat', function (input, pattern = '') {
var dt = new Date(input);
// 獲取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 傳遞進(jìn)來的字符串類型,轉(zhuǎn)為小寫之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否則,就返回 年-月-日 時(shí):分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-$u0z1t8os`;
} else {
// 獲取時(shí)分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-$u0z1t8os ${hh}:${mm}:${ss}`;
}
});
注意:當(dāng)有局部和全局兩個(gè)名稱相同的過濾器時(shí)候,會(huì)以就近原則進(jìn)行調(diào)用,即:局部過濾器優(yōu)先于全局過濾器被調(diào)用!
鍵盤修飾符以及自定義鍵盤修飾符
1.x中自定義鍵盤修飾符【了解即可】
Vue.directive('on').keyCodes.f2 = 113;
2.x中自定義鍵盤修飾符
- 通過
Vue.config.keyCodes.名稱 = 按鍵值來自定義案件修飾符的別名:
Vue.config.keyCodes.f2 = 113;
- 使用自定義的按鍵修飾符:
<input type="text" v-model="name" @keyup.f2="add">
自定義指令
- 自定義全局和局部的 自定義指令:
// 自定義全局指令 v-focus,為綁定的元素自動(dòng)獲取焦點(diǎn):
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用
el.focus();
}
});
// 自定義局部指令 v-color 和 v-font-weight,為綁定的元素設(shè)置指定的字體顏色 和 字體粗細(xì):
directives: {
color: { // 為元素設(shè)置指定的字體顏色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定義指令的簡寫形式,等同于定義了 bind 和 update 兩個(gè)鉤子函數(shù)
el.style.fontWeight = binding2.value;
}
}
- 自定義指令的使用方式:
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">
Vue 1.x 中 自定義元素指令【已廢棄,了解即可】
Vue.elementDirective('red-color', {
bind: function () {
this.el.style.color = 'red';
}
});
使用方式:
<red-color>1232</red-color>
vue實(shí)例的生命周期
- 什么是生命周期:從Vue實(shí)例創(chuàng)建、運(yùn)行、到銷毀期間,總是伴隨著各種各樣的事件,這些事件,統(tǒng)稱為生命周期!
- 生命周期鉤子:就是生命周期事件的別名而已;
- 生命周期鉤子 = 生命周期函數(shù) = 生命周期事件
- 主要的生命周期函數(shù)分類:
- 創(chuàng)建期間的生命周期函數(shù):
- beforeCreate:實(shí)例剛在內(nèi)存中被創(chuàng)建出來,此時(shí),還沒有初始化好 data 和 methods 屬性
- created:實(shí)例已經(jīng)在內(nèi)存中創(chuàng)建OK,此時(shí) data 和 methods 已經(jīng)創(chuàng)建OK,此時(shí)還沒有開始 編譯模板
- beforeMount:此時(shí)已經(jīng)完成了模板的編譯,但是還沒有掛載到頁面中
- mounted:此時(shí),已經(jīng)將編譯好的模板,掛載到了頁面指定的容器中顯示
- 運(yùn)行期間的生命周期函數(shù):
- beforeUpdate:狀態(tài)更新之前執(zhí)行此函數(shù), 此時(shí) data 中的狀態(tài)值是最新的,但是界面上顯示的 數(shù)據(jù)還是舊的,因?yàn)榇藭r(shí)還沒有開始重新渲染DOM節(jié)點(diǎn)
- updated:實(shí)例更新完畢之后調(diào)用此函數(shù),此時(shí) data 中的狀態(tài)值 和 界面上顯示的數(shù)據(jù),都已經(jīng)完成了更新,界面已經(jīng)被重新渲染好了!
- 銷毀期間的生命周期函數(shù):
- beforeDestroy:實(shí)例銷毀之前調(diào)用。在這一步,實(shí)例仍然完全可用。
- destroyed:Vue 實(shí)例銷毀后調(diào)用。調(diào)用后,Vue 實(shí)例指示的所有東西都會(huì)解綁定,所有的事件監(jiān)聽器會(huì)被移除,所有的子實(shí)例也會(huì)被銷毀。
vue-resource 實(shí)現(xiàn) get, post, jsonp請求
除了 vue-resource 之外,還可以使用 axios 的第三方包實(shí)現(xiàn)實(shí)現(xiàn)數(shù)據(jù)的請求
- 之前的學(xué)習(xí)中,如何發(fā)起數(shù)據(jù)請求?
- 常見的數(shù)據(jù)請求類型? get post jsonp
- 測試的URL請求資源地址:
- get請求地址: http://vue.studyit.io/api/getlunbo
- post請求地址:http://vue.studyit.io/api/post
- jsonp請求地址:http://vue.studyit.io/api/jsonp
- JSONP的實(shí)現(xiàn)原理
- 由于瀏覽器的安全性限制,不允許AJAX訪問 協(xié)議不同、域名不同、端口號不同的 數(shù)據(jù)接口,瀏覽器認(rèn)為這種訪問不安全;
- 可以通過動(dòng)態(tài)創(chuàng)建script標(biāo)簽的形式,把script標(biāo)簽的src屬性,指向數(shù)據(jù)接口的地址,因?yàn)閟cript標(biāo)簽不存在跨域限制,這種數(shù)據(jù)獲取方式,稱作JSONP(注意:根據(jù)JSONP的實(shí)現(xiàn)原理,知曉,JSONP只支持Get請求);
- 具體實(shí)現(xiàn)過程:
- 先在客戶端定義一個(gè)回調(diào)方法,預(yù)定義對數(shù)據(jù)的操作;
- 再把這個(gè)回調(diào)方法的名稱,通過URL傳參的形式,提交到服務(wù)器的數(shù)據(jù)接口;
- 服務(wù)器數(shù)據(jù)接口組織好要發(fā)送給客戶端的數(shù)據(jù),再拿著客戶端傳遞過來的回調(diào)方法名稱,拼接出一個(gè)調(diào)用這個(gè)方法的字符串,發(fā)送給客戶端去解析執(zhí)行;
- 客戶端拿到服務(wù)器返回的字符串之后,當(dāng)作Script腳本去解析執(zhí)行,這樣就能夠拿到JSONP的數(shù)據(jù)了;
- 帶大家通過 Node.js ,來手動(dòng)實(shí)現(xiàn)一個(gè)JSONP的請求例子;
const http = require('http');
// 導(dǎo)入解析 URL 地址的核心模塊
const urlModule = require('url');
const server = http.createServer();
// 監(jiān)聽 服務(wù)器的 request 請求事件,處理每個(gè)請求
server.on('request', (req, res) => {
const url = req.url;
// 解析客戶端請求的URL地址
var info = urlModule.parse(url, true);
// 如果請求的 URL 地址是 /getjsonp ,則表示要獲取JSONP類型的數(shù)據(jù)
if (info.pathname === '/getjsonp') {
// 獲取客戶端指定的回調(diào)函數(shù)的名稱
var cbName = info.query.callback;
// 手動(dòng)拼接要返回給客戶端的數(shù)據(jù)對象
var data = {
name: 'zs',
age: 22,
gender: '男',
hobby: ['吃飯', '睡覺', '運(yùn)動(dòng)']
}
// 拼接出一個(gè)方法的調(diào)用,在調(diào)用這個(gè)方法的時(shí)候,把要發(fā)送給客戶端的數(shù)據(jù),序列化為字符串,作為參數(shù)傳遞給這個(gè)調(diào)用的方法:
var result = `${cbName}(${JSON.stringify(data)})`;
// 將拼接好的方法的調(diào)用,返回給客戶端去解析執(zhí)行
res.end(result);
} else {
res.end('404');
}
});
server.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000');
});
- vue-resource 的配置步驟:
- 直接在頁面中,通過
script標(biāo)簽,引入vue-resource的腳本文件; - 注意:引用的先后順序是:先引用
Vue的腳本文件,再引用vue-resource的腳本文件;
- 發(fā)送get請求:
getInfo() { // get 方式獲取數(shù)據(jù)
this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
console.log(res.body);
})
}
- 發(fā)送post請求:
postInfo() {
var url = 'http://127.0.0.1:8899/api/post';
// post 方法接收三個(gè)參數(shù):
// 參數(shù)1: 要請求的URL地址
// 參數(shù)2: 要發(fā)送的數(shù)據(jù)對象
// 參數(shù)3: 指定post提交的編碼類型為 application/x-www-form-urlencoded
this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => {
console.log(res.body);
});
}
- 發(fā)送JSONP請求獲取數(shù)據(jù):
jsonpInfo() { // JSONP形式從服務(wù)器獲取數(shù)據(jù)
var url = 'http://127.0.0.1:8899/api/jsonp';
this.$http.jsonp(url).then(res => {
console.log(res.body);
});
}
配置本地?cái)?shù)據(jù)庫和數(shù)據(jù)接口API
- 先解壓安裝
PHPStudy; - 解壓安裝
Navicat這個(gè)數(shù)據(jù)庫可視化工具,并激活; - 打開
Navicat工具,新建空白數(shù)據(jù)庫,名為dtcmsdb4; - 雙擊新建的數(shù)據(jù)庫,連接上這個(gè)空白數(shù)據(jù)庫,在新建的數(shù)據(jù)庫上
右鍵->運(yùn)行SQL文件,選擇并執(zhí)行dtcmsdb4.sql這個(gè)數(shù)據(jù)庫腳本文件;如果執(zhí)行不報(bào)錯(cuò),則數(shù)據(jù)庫導(dǎo)入完成; - 進(jìn)入文件夾
vuecms3_nodejsapi內(nèi)部,執(zhí)行npm i安裝所有的依賴項(xiàng); - 先確保本機(jī)安裝了
nodemon, 沒有安裝,則運(yùn)行npm i nodemon -g進(jìn)行全局安裝,安裝完畢后,進(jìn)入到vuecms3_nodejsapi目錄 ->src目錄 -> 雙擊運(yùn)行start.bat - 如果API啟動(dòng)失敗,請檢查 PHPStudy 是否正常開啟,同時(shí),檢查
app.js中第14行中數(shù)據(jù)庫連接配置字符串是否正確;PHPStudy 中默認(rèn)的 用戶名是root,默認(rèn)的密碼也是root
品牌管理改造
展示品牌列表
添加品牌數(shù)據(jù)
刪除品牌數(shù)據(jù)
Vue中的動(dòng)畫
為什么要有動(dòng)畫:動(dòng)畫能夠提高用戶的體驗(yàn),幫助用戶更好的理解頁面中的功能;
使用過渡類名
- HTML結(jié)構(gòu):
<div id="app">
<input type="button" value="動(dòng)起來" @click="myAnimate">
<!-- 使用 transition 將需要過渡的元素包裹起來 -->
<transition name="fade">
<div v-show="isshow">動(dòng)畫哦</div>
</transition>
</div>
- VM 實(shí)例:
// 創(chuàng)建 Vue 實(shí)例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
isshow: false
},
methods: {
myAnimate() {
this.isshow = !this.isshow;
}
}
});
- 定義兩組類樣式:
/* 定義進(jìn)入和離開時(shí)候的過渡狀態(tài) */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定義進(jìn)入過渡的開始狀態(tài) 和 離開過渡的結(jié)束狀態(tài) */
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100px);
}
使用第三方 CSS 動(dòng)畫庫
- 導(dǎo)入動(dòng)畫類庫:
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
- 定義 transition 及屬性:
<transition
enter-active-class="fadeInRight"
leave-active-class="fadeOutRight"
:duration="{ enter: 500, leave: 800 }">
<div class="animated" v-show="isshow">動(dòng)畫哦</div>
</transition>
使用動(dòng)畫鉤子函數(shù)
- 定義 transition 組件以及三個(gè)鉤子函數(shù):
<div id="app">
<input type="button" value="切換動(dòng)畫" @click="isshow = !isshow">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div v-if="isshow" class="show">OK</div>
</transition>
</div>
- 定義三個(gè) methods 鉤子方法:
methods: {
beforeEnter(el) { // 動(dòng)畫進(jìn)入之前的回調(diào)
el.style.transform = 'translateX(500px)';
},
enter(el, done) { // 動(dòng)畫進(jìn)入完成時(shí)候的回調(diào)
el.offsetWidth;
el.style.transform = 'translateX(0px)';
done();
},
afterEnter(el) { // 動(dòng)畫進(jìn)入完成之后的回調(diào)
this.isshow = !this.isshow;
}
}
- 定義動(dòng)畫過渡時(shí)長和樣式:
.show{
transition: all 0.4s ease;
}
v-for 的列表過渡
- 定義過渡樣式:
<style>
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
</style>
- 定義DOM結(jié)構(gòu),其中,需要使用 transition-group 組件把v-for循環(huán)的列表包裹起來:
<div id="app">
<input type="text" v-model="txt" @keyup.enter="add">
<transition-group tag="ul" name="list">
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</transition-group>
</div>
- 定義 VM中的結(jié)構(gòu):
// 創(chuàng)建 Vue 實(shí)例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
txt: '',
list: [1, 2, 3, 4]
},
methods: {
add() {
this.list.push(this.txt);
this.txt = '';
}
}
});
列表的排序過渡
<transition-group> 組件還有一個(gè)特殊之處。不僅可以進(jìn)入和離開動(dòng)畫,還可以改變定位。要使用這個(gè)新功能只需了解新增的 v-move 特性,它會(huì)在元素的改變定位的過程中應(yīng)用。
-
v-move和v-leave-active結(jié)合使用,能夠讓列表的過渡更加平緩柔和:
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}