Vue.js - Day1
課程介紹
前5天: 都在學習Vue基本的語法和概念;打包工具 Webpack , Gulp
後5天: 以項目驅動教學;
什麼是Vue.js
-
Vue.js 是目前最火的一個前端框架,React是最流行的一個前端框架(React除了開發網站,還可以開發手機App, Vue語法也是可以用於進行手機App開發的,需要藉助於Weex)
-
Vue.js 是前端的主流框架之一,和Angular.js、React.js 一起,併成爲前端三大主流框架!
-
Vue.js 是一套構建用戶界面的框架,只關注視圖層,它不僅易於上手,還便於與第三方庫或既有項目整合。(Vue有配套的第三方類庫,可以整合起來做大型項目的開發)
-
前端的主要工作?主要負責MVC中的V這一層;主要工作就是和界面打交道,來製作前端頁面效果;
爲什麼要學習流行框架
- 企業爲了提高開發效率:在企業中,時間就是效率,效率就是金錢;
- 企業中,使用框架,能夠提高開發的效率;
-
提高開發效率的發展歷程:原生JS -> Jquery之類的類庫 -> 前端模板引擎 -> Angular.js / Vue.js(能夠幫助我們減少不必要的DOM操作;提高渲染效率;雙向數據綁定的概念【通過框架提供的指令,我們前端程序員只需要關心數據的業務邏輯,不再關心DOM是如何渲染的了】)
-
在Vue中,一個核心的概念,就是讓用戶不再操作DOM元素,解放了用戶的雙手,讓程序員可以更多的時間去關注業務邏輯;
-
增強自己就業時候的競爭力
- 人無我有,人有我優
- 你平時不忙的時候,都在幹嘛?
框架和庫的區別
- 框架:是一套完整的解決方案;對項目的侵入性較大,項目如果需要更換框架,則需要重新架構整個項目。
- node 中的 express;
- 庫(插件):提供某一個小功能,對項目的侵入性較小,如果某個庫無法完成某些需求,可以很容易切換到其它庫實現需求。
-
- 從Jquery 切換到 Zepto
-
- 從 EJS 切換到 art-template
Node(後端)中的 MVC 與 前端中的 MVVM 之間的區別
-
MVC 是後端的分層開發概念;
-
MVVM是前端視圖層的概念,主要關注於 視圖層分離,也就是說:MVVM把前端的視圖層,分爲了 三部分 Model, View , VM ViewModel
-
爲什麼有了MVC還要有MVVM
Vue.js 基本代碼 和 MVVM 之間的對應關係
Vue之 - 基本的代碼結構
和插值表達式
、v-cloak
Vue指令之v-text
和v-html
Vue指令之v-bind
的三種用法
-
直接使用指令
v-bind
-
使用簡化指令
:
-
在綁定的時候,拼接綁定內容:
:title="btnTitle + ', 這是追加的內容'"
Vue指令之v-on
和跑馬燈效果
跑馬燈效果
- HTML結構:
<div id="app">
<p>{{info}}</p>
<input type="button" value="開啓" v-on:click="go">
<input type="button" value="停止" v-on:click="stop">
</div>
- Vue實例:
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
info: '猥瑣發育,別浪~!',
intervalId: null
},
methods: {
go() {
// 如果當前有定時器在運行,則直接return
if (this.intervalId != null) {
return;
}
// 開始定時器
this.intervalId = setInterval(() => {
this.info = this.info.substring(1) + this.info.substring(0, 1);
}, 500);
},
stop() {
clearInterval(this.intervalId);
}
}
});
Vue指令之v-on的縮寫
和事件修飾符
事件修飾符:
-
.stop 阻止冒泡
-
.prevent 阻止默認事件
-
.capture 添加事件偵聽器時使用事件捕獲模式
-
.self 只當事件在該元素本身(比如不是子元素)觸發時觸發回調
-
.once 事件只觸發一次
Vue指令之v-model
和雙向數據綁定
簡易計算器案例
- HTML 代碼結構
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="0">+</option>
<option value="1">-</option>
<option value="2">*</option>
<option value="3">÷</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" v-on:click="getResult">
<input type="text" v-model="result">
</div>
- Vue實例代碼:
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
n1: 0,
n2: 0,
result: 0,
opt: '0'
},
methods: {
getResult() {
switch (this.opt) {
case '0':
this.result = parseInt(this.n1) + parseInt(this.n2);
break;
case '1':
this.result = parseInt(this.n1) - parseInt(this.n2);
break;
case '2':
this.result = parseInt(this.n1) * parseInt(this.n2);
break;
case '3':
this.result = parseInt(this.n1) / parseInt(this.n2);
break;
}
}
}
});
在Vue中使用樣式
使用class樣式
- 數組
<h1 :class="['red', 'thin']">這是一個邪惡的H1</h1>
- 數組中使用三元表達式
<h1 :class="['red', 'thin', isactive?'active':'']">這是一個邪惡的H1</h1>
- 數組中嵌套對象
<h1 :class="['red', 'thin', {'active': isactive}]">這是一個邪惡的H1</h1>
- 直接使用對象
<h1 :class="{red:true, italic:true, active:true, thin:true}">這是一個邪惡的H1</h1>
使用內聯樣式
- 直接在元素上通過
:style
的形式,書寫樣式對象
<h1 :style="{color: 'red', 'font-size': '40px'}">這是一個善良的H1</h1>
- 將樣式對象,定義到
data
中,並直接引用到:style
中
- 在data上定義樣式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }
}
- 在元素中,通過屬性綁定的形式,將樣式對象應用到元素中:
<h1 :style="h1StyleObj">這是一個善良的H1</h1>
- 在
:style
中通過數組,引用多個data
上的樣式對象
- 在data上定義樣式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },
h1StyleObj2: { fontStyle: 'italic' }
}
- 在元素中,通過屬性綁定的形式,將樣式對象應用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">這是一個善良的H1</h1>
Vue指令之v-for
和key
屬性
- 迭代數組
<ul>
<li v-for="(item, i) in list">索引:{{i}} --- 姓名:{{item.name}} --- 年齡:{{item.age}}</li>
</ul>
- 迭代對象中的屬性
<!-- 循環遍歷對象身上的屬性 -->
<div v-for="(val, key, i) in userInfo">{{val}} --- {{key}} --- {{i}}</div>
- 迭代數字
<p v-for="i in 10">這是第 {{i}} 個P標籤</p>
2.2.0+ 的版本里,當在組件中使用 v-for 時,key 現在是必須的。
當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用 “就地複用” 策略。如果數據項的順序被改變,Vue將不是移動 DOM 元素來匹配數據項的順序, 而是簡單複用此處每個元素,並且確保它在特定索引下顯示已被渲染過的每個元素。
爲了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要爲每項提供一個唯一 key 屬性。
Vue指令之v-if
和v-show
一般來說,v-if 有更高的切換消耗而 v-show 有更高的初始渲染消耗。因此,如果需要頻繁切換 v-show 較好,如果在運行時條件不大可能改變 v-if 較好。
品牌管理案例
添加新品牌
刪除品牌
根據條件篩選品牌
- 1.x 版本中的filterBy指令,在2.x中已經被廢除:
<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版本中手動實現篩選的方式:
- 篩選框綁定到 VM 實例中的
searchName
屬性:
<hr> 輸入篩選名稱:
<input type="text" v-model="searchName">
- 在使用
v-for
指令循環每一行數據的時候,不再直接item in list
,而是in
一個 過濾的methods 方法,同時,把過濾條件searchName
傳遞進去:
<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
過濾方法中,使用 數組的filter
方法進行過濾:
search(name) {
return this.list.filter(x => {
return x.name.indexOf(name) != -1;
});
}
Vue調試工具vue-devtools
的安裝步驟和使用
過濾器
概念:Vue.js 允許你自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個地方:mustache 插值和 v-bind 表達式。過濾器應該被添加在 JavaScript 表達式的尾部,由“管道”符指示;
私有過濾器
- HTML元素:
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
- 私有
filters
定義方式:
filters: { // 私有局部過濾器,只能在 當前 VM 對象所控制的 View 區域進行使用
dataFormat(input, pattern = "") { // 在參數列表中 通過 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');
// 如果 傳遞進來的字符串類型,轉爲小寫之後,等於 yyyy-mm-dd,那麼就返回 年-月-日
// 否則,就返回 年-月-日 時:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 獲取時分秒
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}-${d} ${hh}:${mm}:${ss}`;
}
}
}
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)來填充字符串;
全局過濾器
// 定義一個全局過濾器
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');
// 如果 傳遞進來的字符串類型,轉爲小寫之後,等於 yyyy-mm-dd,那麼就返回 年-月-日
// 否則,就返回 年-月-日 時:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 獲取時分秒
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}-${d} ${hh}:${mm}:${ss}`;
}
});
注意:當有局部和全局兩個名稱相同的過濾器時候,會以就近原則進行調用,即:局部過濾器優先於全局過濾器被調用!
鍵盤修飾符以及自定義鍵盤修飾符
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,爲綁定的元素自動獲取焦點:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被綁定元素插入父節點時調用
el.focus();
}
});
// 自定義局部指令 v-color 和 v-font-weight,爲綁定的元素設置指定的字體顏色 和 字體粗細:
directives: {
color: { // 爲元素設置指定的字體顏色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定義指令的簡寫形式,等同於定義了 bind 和 update 兩個鉤子函數
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.js 1.x 文檔
- vue.js 2.x 文檔
- String.prototype.padStart(maxLength, fillString)
- js 裏面的鍵盤事件對應的鍵碼
- Vue.js雙向綁定的實現原理
Vue.js - Day2
品牌管理案例
添加新品牌
刪除品牌
根據條件篩選品牌
- 1.x 版本中的filterBy指令,在2.x中已經被廢除:
<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版本中手動實現篩選的方式:
- 篩選框綁定到 VM 實例中的
searchName
屬性:
<hr> 輸入篩選名稱:
<input type="text" v-model="searchName">
- 在使用
v-for
指令循環每一行數據的時候,不再直接item in list
,而是in
一個 過濾的methods 方法,同時,把過濾條件searchName
傳遞進去:
<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
過濾方法中,使用 數組的filter
方法進行過濾:
search(name) {
return this.list.filter(x => {
return x.name.indexOf(name) != -1;
});
}
Vue調試工具vue-devtools
的安裝步驟和使用
過濾器
概念:Vue.js 允許你自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個地方:mustache 插值和 v-bind 表達式。過濾器應該被添加在 JavaScript 表達式的尾部,由“管道”符指示;
私有過濾器
- HTML元素:
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
- 私有
filters
定義方式:
filters: { // 私有局部過濾器,只能在 當前 VM 對象所控制的 View 區域進行使用
dataFormat(input, pattern = "") { // 在參數列表中 通過 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');
// 如果 傳遞進來的字符串類型,轉爲小寫之後,等於 yyyy-mm-dd,那麼就返回 年-月-日
// 否則,就返回 年-月-日 時:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 獲取時分秒
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}-${d} ${hh}:${mm}:${ss}`;
}
}
}
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)來填充字符串;
全局過濾器
// 定義一個全局過濾器
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');
// 如果 傳遞進來的字符串類型,轉爲小寫之後,等於 yyyy-mm-dd,那麼就返回 年-月-日
// 否則,就返回 年-月-日 時:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 獲取時分秒
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}-${d} ${hh}:${mm}:${ss}`;
}
});
注意:當有局部和全局兩個名稱相同的過濾器時候,會以就近原則進行調用,即:局部過濾器優先於全局過濾器被調用!
鍵盤修飾符以及自定義鍵盤修飾符
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,爲綁定的元素自動獲取焦點:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被綁定元素插入父節點時調用
el.focus();
}
});
// 自定義局部指令 v-color 和 v-font-weight,爲綁定的元素設置指定的字體顏色 和 字體粗細:
directives: {
color: { // 爲元素設置指定的字體顏色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定義指令的簡寫形式,等同於定義了 bind 和 update 兩個鉤子函數
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實例的生命週期
- 什麼是生命週期:從Vue實例創建、運行、到銷燬期間,總是伴隨着各種各樣的事件,這些事件,統稱爲生命週期!
- 生命週期鉤子:就是生命週期事件的別名而已;
- 生命週期鉤子 = 生命週期函數 = 生命週期事件
- 主要的生命週期函數分類:
- 創建期間的生命週期函數:
- beforeCreate:實例剛在內存中被創建出來,此時,還沒有初始化好 data 和 methods 屬性
- created:實例已經在內存中創建OK,此時 data 和 methods 已經創建OK,此時還沒有開始 編譯模板
- beforeMount:此時已經完成了模板的編譯,但是還沒有掛載到頁面中
- mounted:此時,已經將編譯好的模板,掛載到了頁面指定的容器中顯示
- 運行期間的生命週期函數:
- beforeUpdate:狀態更新之前執行此函數, 此時 data 中的狀態值是最新的,但是界面上顯示的 數據還是舊的,因爲此時還沒有開始重新渲染DOM節點
- updated:實例更新完畢之後調用此函數,此時 data 中的狀態值 和 界面上顯示的數據,都已經完成了更新,界面已經被重新渲染好了!
- 銷燬期間的生命週期函數:
- beforeDestroy:實例銷燬之前調用。在這一步,實例仍然完全可用。
- destroyed:Vue 實例銷燬後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬。
vue-resource 實現 get, post, jsonp請求
除了 vue-resource 之外,還可以使用 axios
的第三方包實現實現數據的請求
- 之前的學習中,如何發起數據請求?
- 常見的數據請求類型? 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的實現原理
- 由於瀏覽器的安全性限制,不允許AJAX訪問 協議不同、域名不同、端口號不同的 數據接口,瀏覽器認爲這種訪問不安全;
- 可以通過動態創建script標籤的形式,把script標籤的src屬性,指向數據接口的地址,因爲script標籤不存在跨域限制,這種數據獲取方式,稱作JSONP(注意:根據JSONP的實現原理,知曉,JSONP只支持Get請求);
- 具體實現過程:
- 先在客戶端定義一個回調方法,預定義對數據的操作;
- 再把這個回調方法的名稱,通過URL傳參的形式,提交到服務器的數據接口;
- 服務器數據接口組織好要發送給客戶端的數據,再拿着客戶端傳遞過來的回調方法名稱,拼接出一個調用這個方法的字符串,發送給客戶端去解析執行;
- 客戶端拿到服務器返回的字符串之後,當作Script腳本去解析執行,這樣就能夠拿到JSONP的數據了;
- 帶大家通過 Node.js ,來手動實現一個JSONP的請求例子;
const http = require('http');
// 導入解析 URL 地址的核心模塊
const urlModule = require('url');
const server = http.createServer();
// 監聽 服務器的 request 請求事件,處理每個請求
server.on('request', (req, res) => {
const url = req.url;
// 解析客戶端請求的URL地址
var info = urlModule.parse(url, true);
// 如果請求的 URL 地址是 /getjsonp ,則表示要獲取JSONP類型的數據
if (info.pathname === '/getjsonp') {
// 獲取客戶端指定的回調函數的名稱
var cbName = info.query.callback;
// 手動拼接要返回給客戶端的數據對象
var data = {
name: 'zs',
age: 22,
gender: '男',
hobby: ['吃飯', '睡覺', '運動']
}
// 拼接出一個方法的調用,在調用這個方法的時候,把要發送給客戶端的數據,序列化爲字符串,作爲參數傳遞給這個調用的方法:
var result = `${cbName}(${JSON.stringify(data)})`;
// 將拼接好的方法的調用,返回給客戶端去解析執行
res.end(result);
} else {
res.end('404');
}
});
server.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000');
});
- vue-resource 的配置步驟:
- 直接在頁面中,通過
script
標籤,引入vue-resource
的腳本文件; - 注意:引用的先後順序是:先引用
Vue
的腳本文件,再引用vue-resource
的腳本文件;
- 發送get請求:
getInfo() { // get 方式獲取數據
this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
console.log(res.body);
})
}
- 發送post請求:
postInfo() {
var url = 'http://127.0.0.1:8899/api/post';
// post 方法接收三個參數:
// 參數1: 要請求的URL地址
// 參數2: 要發送的數據對象
// 參數3: 指定post提交的編碼類型爲 application/x-www-form-urlencoded
this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => {
console.log(res.body);
});
}
- 發送JSONP請求獲取數據:
jsonpInfo() { // JSONP形式從服務器獲取數據
var url = 'http://127.0.0.1:8899/api/jsonp';
this.$http.jsonp(url).then(res => {
console.log(res.body);
});
}
配置本地數據庫和數據接口API
- 先解壓安裝
PHPStudy
; - 解壓安裝
Navicat
這個數據庫可視化工具,並激活; - 打開
Navicat
工具,新建空白數據庫,名爲dtcmsdb4
; - 雙擊新建的數據庫,連接上這個空白數據庫,在新建的數據庫上
右鍵
->運行SQL文件
,選擇並執行dtcmsdb4.sql
這個數據庫腳本文件;如果執行不報錯,則數據庫導入完成; - 進入文件夾
vuecms3_nodejsapi
內部,執行npm i
安裝所有的依賴項; - 先確保本機安裝了
nodemon
, 沒有安裝,則運行npm i nodemon -g
進行全局安裝,安裝完畢後,進入到vuecms3_nodejsapi
目錄 ->src
目錄 -> 雙擊運行start.bat
- 如果API啓動失敗,請檢查 PHPStudy 是否正常開啓,同時,檢查
app.js
中第14行
中數據庫連接配置字符串是否正確;PHPStudy 中默認的 用戶名是root,默認的密碼也是root
品牌管理改造
展示品牌列表
添加品牌數據
刪除品牌數據
Vue中的動畫
爲什麼要有動畫:動畫能夠提高用戶的體驗,幫助用戶更好的理解頁面中的功能;
使用過渡類名
- HTML結構:
<div id="app">
<input type="button" value="動起來" @click="myAnimate">
<!-- 使用 transition 將需要過渡的元素包裹起來 -->
<transition name="fade">
<div v-show="isshow">動畫哦</div>
</transition>
</div>
- VM 實例:
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
isshow: false
},
methods: {
myAnimate() {
this.isshow = !this.isshow;
}
}
});
- 定義兩組類樣式:
/* 定義進入和離開時候的過渡狀態 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定義進入過渡的開始狀態 和 離開過渡的結束狀態 */
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100px);
}
使用第三方 CSS 動畫庫
- 導入動畫類庫:
<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">動畫哦</div>
</transition>
使用動畫鉤子函數
- 定義 transition 組件以及三個鉤子函數:
<div id="app">
<input type="button" value="切換動畫" @click="isshow = !isshow">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div v-if="isshow" class="show">OK</div>
</transition>
</div>
- 定義三個 methods 鉤子方法:
methods: {
beforeEnter(el) { // 動畫進入之前的回調
el.style.transform = 'translateX(500px)';
},
enter(el, done) { // 動畫進入完成時候的回調
el.offsetWidth;
el.style.transform = 'translateX(0px)';
done();
},
afterEnter(el) { // 動畫進入完成之後的回調
this.isshow = !this.isshow;
}
}
- 定義動畫過渡時長和樣式:
.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結構,其中,需要使用 transition-group 組件把v-for循環的列表包裹起來:
<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中的結構:
// 創建 Vue 實例,得到 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>
組件還有一個特殊之處。不僅可以進入和離開動畫,還可以改變定位。要使用這個新功能只需瞭解新增的 v-move
特性,它會在元素的改變定位的過程中應用。
v-move
和v-leave-active
結合使用,能夠讓列表的過渡更加平緩柔和:
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}
相關文章
- vue.js 1.x 文檔
- vue.js 2.x 文檔
- String.prototype.padStart(maxLength, fillString)
- js 裏面的鍵盤事件對應的鍵碼
- pagekit/vue-resource
- navicat如何導入sql文件和導出sql文件
- 貝塞爾在線生成器
Vue.js - Day3
定義Vue組件
什麼是組件: 組件的出現,就是爲了拆分Vue實例的代碼量的,能夠讓我們以不同的組件,來劃分不同的功能模塊,將來我們需要什麼樣的功能,就可以去調用對應的組件即可;
組件化和模塊化的不同:
- 模塊化: 是從代碼邏輯的角度進行劃分的;方便代碼分層開發,保證每個功能模塊的職能單一;
- 組件化: 是從UI界面的角度進行劃分的;前端的組件化,方便UI組件的重用;
全局組件定義的三種方式
- 使用 Vue.extend 配合 Vue.component 方法:
var login = Vue.extend({
template: '<h1>登錄</h1>'
});
Vue.component('login', login);
- 直接使用 Vue.component 方法:
Vue.component('register', {
template: '<h1>註冊</h1>'
});
- 將模板字符串,定義到script標籤種:
<script id="tmpl" type="x-template">
<div><a href="#">登錄</a> | <a href="#">註冊</a></div>
</script>
同時,需要使用 Vue.component 來定義組件:
Vue.component('account', {
template: '#tmpl'
});
注意: 組件中的DOM結構,有且只能有唯一的根元素(Root Element)來進行包裹!
組件中展示數據和響應事件
- 在組件中,
data
需要被定義爲一個方法,例如:
Vue.component('account', {
template: '#tmpl',
data() {
return {
msg: '大家好!'
}
},
methods:{
login(){
alert('點擊了登錄按鈕');
}
}
});
- 在子組件中,如果將模板字符串,定義到了script標籤中,那麼,要訪問子組件身上的
data
屬性中的值,需要使用this
來訪問;
【重點】爲什麼組件中的data屬性必須定義爲一個方法並返回一個對象
- 通過計數器案例演示
使用components
屬性定義局部子組件
- 組件實例定義方式:
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: { // 定義子組件
account: { // account 組件
template: '<div><h1>這是Account組件{{name}}</h1><login></login></div>', // 在這裏使用定義的子組件
components: { // 定義子組件的子組件
login: { // login 組件
template: "<h3>這是登錄組件</h3>"
}
}
}
}
});
</script>
- 引用組件:
<div id="app">
<account></account>
</div>
使用flag
標識符結合v-if
和v-else
切換組件
- 頁面結構:
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<my-com1 v-if="flag"></my-com1>
<my-com2 v-else="flag"></my-com2>
</div>
- Vue實例定義:
<script>
Vue.component('myCom1', {
template: '<h3>奔波霸</h3>'
})
Vue.component('myCom2', {
template: '<h3>霸波奔</h3>'
})
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: true
},
methods: {}
});
</script>
使用:is
屬性來切換不同的子組件,並添加切換動畫
- 組件實例定義方式:
// 登錄組件
const login = Vue.extend({
template: `<div>
<h3>登錄組件</h3>
</div>`
});
Vue.component('login', login);
// 註冊組件
const register = Vue.extend({
template: `<div>
<h3>註冊組件</h3>
</div>`
});
Vue.component('register', register);
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: { comName: 'login' },
methods: {}
});
- 使用
component
標籤,來引用組件,並通過:is
屬性來指定要加載的組件:
<div id="app">
<a href="#" @click.prevent="comName='login'">登錄</a>
<a href="#" @click.prevent="comName='register'">註冊</a>
<hr>
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
- 添加切換樣式:
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(30px);
}
.v-enter-active,
.v-leave-active {
position: absolute;
transition: all 0.3s ease;
}
h3{
margin: 0;
}
</style>
父組件向子組件傳值
- 組件實例定義方式,注意:一定要使用
props
屬性來定義父組件傳遞過來的數據
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: '這是父組件中的消息'
},
components: {
son: {
template: '<h1>這是子組件 --- {{finfo}}</h1>',
props: ['finfo']
}
}
});
</script>
- 使用
v-bind
或簡化指令,將數據傳遞到子組件中:
<div id="app">
<son :finfo="msg"></son>
</div>
子組件向父組件傳值
- 原理:父組件將方法的引用,傳遞到子組件內部,子組件在內部調用父組件傳遞過來的方法,同時把要發送給父組件的數據,在調用方法的時候當作參數傳遞進去;
- 父組件將方法的引用傳遞給子組件,其中,
getMsg
是父組件中methods
中定義的方法名稱,func
是子組件調用傳遞過來方法時候的方法名稱
<son @func="getMsg"></son>
- 子組件內部通過
this.$emit('方法名', 要傳遞的數據)
方式,來調用父組件中的方法,同時把數據傳遞給父組件使用
<div id="app">
<!-- 引用父組件 -->
<son @func="getMsg"></son>
<!-- 組件模板定義 -->
<script type="x-template" id="son">
<div>
<input type="button" value="向父組件傳值" @click="sendMsg" />
</div>
</script>
</div>
<script>
// 子組件的定義方式
Vue.component('son', {
template: '#son', // 組件模板Id
methods: {
sendMsg() { // 按鈕的點擊事件
this.$emit('func', 'OK'); // 調用父組件傳遞過來的方法,同時把數據傳遞出去
}
}
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getMsg(val){ // 子組件中,通過 this.$emit() 實際調用的方法,在此進行定義
alert(val);
}
}
});
</script>
評論列表案例
目標:主要練習父子組件之間傳值
使用 this.$refs
來獲取元素和組件
<div id="app">
<div>
<input type="button" value="獲取元素內容" @click="getElement" />
<!-- 使用 ref 獲取元素 -->
<h1 ref="myh1">這是一個大大的H1</h1>
<hr>
<!-- 使用 ref 獲取子組件 -->
<my-com ref="mycom"></my-com>
</div>
</div>
<script>
Vue.component('my-com', {
template: '<h5>這是一個子組件</h5>',
data() {
return {
name: '子組件'
}
}
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
// 通過 this.$refs 來獲取元素
console.log(this.$refs.myh1.innerText);
// 通過 this.$refs 來獲取組件
console.log(this.$refs.mycom.name);
}
}
});
</script>
什麼是路由
-
對於普通的網站,所有的超鏈接都是URL地址,所有的URL地址都對應服務器上對應的資源;
-
對於單頁面應用程序來說,主要通過URL中的hash(#號)來實現不同頁面之間的切換,同時,hash有一個特點:HTTP請求中不會包含hash相關的內容;所以,單頁面程序中的頁面跳轉主要用hash實現;
-
在單頁面應用程序中,這種通過hash改變來切換頁面的方式,稱作前端路由(區別於後端路由);
在 vue 中使用 vue-router
- 導入 vue-router 組件類庫:
<!-- 1. 導入 vue-router 組件類庫 -->
<script src="./lib/vue-router-2.7.0.js"></script>
- 使用 router-link 組件來導航
<!-- 2. 使用 router-link 組件來導航 -->
<router-link to="/login">登錄</router-link>
<router-link to="/register">註冊</router-link>
- 使用 router-view 組件來顯示匹配到的組件
<!-- 3. 使用 router-view 組件來顯示匹配到的組件 -->
<router-view></router-view>
- 創建使用
Vue.extend
創建組件
// 4.1 使用 Vue.extend 來創建登錄組件
var login = Vue.extend({
template: '<h1>登錄組件</h1>'
});
// 4.2 使用 Vue.extend 來創建註冊組件
var register = Vue.extend({
template: '<h1>註冊組件</h1>'
});
- 創建一個路由 router 實例,通過 routers 屬性來定義路由匹配規則
// 5. 創建一個路由 router 實例,通過 routers 屬性來定義路由匹配規則
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
- 使用 router 屬性來使用路由規則
// 6. 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
router: router // 使用 router 屬性來使用路由規則
});
設置路由高亮
設置路由切換動效
在路由規則中定義參數
- 在規則中定義參數:
{ path: '/register/:id', component: register }
- 通過
this.$route.params
來獲取路由中的參數:
var register = Vue.extend({
template: '<h1>註冊組件 --- {{this.$route.params.id}}</h1>'
});
使用 children
屬性實現路由嵌套
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<script>
// 父路由中的組件
const account = Vue.extend({
template: `<div>
這是account組件
<router-link to="/account/login">login</router-link> |
<router-link to="/account/register">register</router-link>
<router-view></router-view>
</div>`
});
// 子路由中的 login 組件
const login = Vue.extend({
template: '<div>登錄組件</div>'
});
// 子路由中的 register 組件
const register = Vue.extend({
template: '<div>註冊組件</div>'
});
// 路由實例
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/account/login' }, // 使用 redirect 實現路由重定向
{
path: '/account',
component: account,
children: [ // 通過 children 數組屬性,來實現路由的嵌套
{ path: 'login', component: login }, // 注意,子路由的開頭位置,不要加 / 路徑符
{ path: 'register', component: register }
]
}
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
account
},
router: router
});
</script>
命名視圖實現經典佈局
- 標籤代碼結構:
<div id="app">
<router-view></router-view>
<div class="content">
<router-view name="a"></router-view>
<router-view name="b"></router-view>
</div>
</div>
- JS代碼:
<script>
var header = Vue.component('header', {
template: '<div class="header">header</div>'
});
var sidebar = Vue.component('sidebar', {
template: '<div class="sidebar">sidebar</div>'
});
var mainbox = Vue.component('mainbox', {
template: '<div class="mainbox">mainbox</div>'
});
// 創建路由對象
var router = new VueRouter({
routes: [
{
path: '/', components: {
default: header,
a: sidebar,
b: mainbox
}
}
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
- CSS 樣式:
<style>
.header {
border: 1px solid red;
}
.content{
display: flex;
}
.sidebar {
flex: 2;
border: 1px solid green;
height: 500px;
}
.mainbox{
flex: 8;
border: 1px solid blue;
height: 500px;
}
</style>
watch
屬性的使用
考慮一個問題:想要實現 名
和 姓
兩個文本框的內容改變,則全名的文本框中的值也跟着改變;(用以前的知識如何實現???)
- 監聽
data
中屬性的改變:
<div id="app">
<input type="text" v-model="firstName"> +
<input type="text" v-model="lastName"> =
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen',
fullName: 'jack - chen'
},
methods: {},
watch: {
'firstName': function (newVal, oldVal) { // 第一個參數是新數據,第二個參數是舊數據
this.fullName = newVal + ' - ' + this.lastName;
},
'lastName': function (newVal, oldVal) {
this.fullName = this.firstName + ' - ' + newVal;
}
}
});
</script>
- 監聽路由對象的改變:
<div id="app">
<router-link to="/login">登錄</router-link>
<router-link to="/register">註冊</router-link>
<router-view></router-view>
</div>
<script>
var login = Vue.extend({
template: '<h1>登錄組件</h1>'
});
var register = Vue.extend({
template: '<h1>註冊組件</h1>'
});
var router = new VueRouter({
routes: [
{ path: "/login", component: login },
{ path: "/register", component: register }
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: router,
watch: {
'$route': function (newVal, oldVal) {
if (newVal.path === '/login') {
console.log('這是登錄組件');
}
}
}
});
</script>
computed
計算屬性的使用
- 默認只有
getter
的計算屬性:
<div id="app">
<input type="text" v-model="firstName"> +
<input type="text" v-model="lastName"> =
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen'
},
methods: {},
computed: { // 計算屬性; 特點:當計算屬性中所以來的任何一個 data 屬性改變之後,都會重新觸發 本計算屬性 的重新計算,從而更新 fullName 的值
fullName() {
return this.firstName + ' - ' + this.lastName;
}
}
});
</script>
- 定義有
getter
和setter
的計算屬性:
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<!-- 點擊按鈕重新爲 計算屬性 fullName 賦值 -->
<input type="button" value="修改fullName" @click="changeName">
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen'
},
methods: {
changeName() {
this.fullName = 'TOM - chen2';
}
},
computed: {
fullName: {
get: function () {
return this.firstName + ' - ' + this.lastName;
},
set: function (newVal) {
var parts = newVal.split(' - ');
this.firstName = parts[0];
this.lastName = parts[1];
}
}
}
});
</script>
watch
、computed
和methods
之間的對比
computed
屬性的結果會被緩存,除非依賴的響應式屬性變化纔會重新計算。主要當作屬性來使用;methods
方法表示一個具體的操作,主要書寫業務邏輯;watch
一個對象,鍵是需要觀察的表達式,值是對應回調函數。主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操作;可以看作是computed
和methods
的結合體;
nrm
的安裝使用
作用:提供了一些最常用的NPM包鏡像地址,能夠讓我們快速的切換安裝包時候的服務器地址;
什麼是鏡像:原來包剛一開始是隻存在於國外的NPM服務器,但是由於網絡原因,經常訪問不到,這時候,我們可以在國內,創建一個和官網完全一樣的NPM服務器,只不過,數據都是從人家那裏拿過來的,除此之外,使用方式完全一樣;
- 運行
npm i nrm -g
全局安裝nrm
包; - 使用
nrm ls
查看當前所有可用的鏡像源地址以及當前所使用的鏡像源地址; - 使用
nrm use npm
或nrm use taobao
切換不同的鏡像源地址;
相關文件
Vue.js - Day4
父組件向子組件傳值
- 組件實例定義方式,注意:一定要使用
props
屬性來定義父組件傳遞過來的數據
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: '這是父組件中的消息'
},
components: {
son: {
template: '<h1>這是子組件 --- {{finfo}}</h1>',
props: ['finfo']
}
}
});
</script>
- 使用
v-bind
或簡化指令,將數據傳遞到子組件中:
<div id="app">
<son :finfo="msg"></son>
</div>
子組件向父組件傳值
- 原理:父組件將方法的引用,傳遞到子組件內部,子組件在內部調用父組件傳遞過來的方法,同時把要發送給父組件的數據,在調用方法的時候當作參數傳遞進去;
- 父組件將方法的引用傳遞給子組件,其中,
getMsg
是父組件中methods
中定義的方法名稱,func
是子組件調用傳遞過來方法時候的方法名稱
<son @func="getMsg"></son>
- 子組件內部通過
this.$emit('方法名', 要傳遞的數據)
方式,來調用父組件中的方法,同時把數據傳遞給父組件使用
<div id="app">
<!-- 引用父組件 -->
<son @func="getMsg"></son>
<!-- 組件模板定義 -->
<script type="x-template" id="son">
<div>
<input type="button" value="向父組件傳值" @click="sendMsg" />
</div>
</script>
</div>
<script>
// 子組件的定義方式
Vue.component('son', {
template: '#son', // 組件模板Id
methods: {
sendMsg() { // 按鈕的點擊事件
this.$emit('func', 'OK'); // 調用父組件傳遞過來的方法,同時把數據傳遞出去
}
}
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getMsg(val){ // 子組件中,通過 this.$emit() 實際調用的方法,在此進行定義
alert(val);
}
}
});
</script>
組件中data和props的區別
評論列表案例
目標:主要練習父子組件之間傳值
使用 this.$refs
來獲取元素和組件
<div id="app">
<div>
<input type="button" value="獲取元素內容" @click="getElement" />
<!-- 使用 ref 獲取元素 -->
<h1 ref="myh1">這是一個大大的H1</h1>
<hr>
<!-- 使用 ref 獲取子組件 -->
<my-com ref="mycom"></my-com>
</div>
</div>
<script>
Vue.component('my-com', {
template: '<h5>這是一個子組件</h5>',
data() {
return {
name: '子組件'
}
}
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getElement() {
// 通過 this.$refs 來獲取元素
console.log(this.$refs.myh1.innerText);
// 通過 this.$refs 來獲取組件
console.log(this.$refs.mycom.name);
}
}
});
</script>
什麼是路由
-
**後端路由:**對於普通的網站,所有的超鏈接都是URL地址,所有的URL地址都對應服務器上對應的資源;
-
**前端路由:**對於單頁面應用程序來說,主要通過URL中的hash(#號)來實現不同頁面之間的切換,同時,hash有一個特點:HTTP請求中不會包含hash相關的內容;所以,單頁面程序中的頁面跳轉主要用hash實現;
-
在單頁面應用程序中,這種通過hash改變來切換頁面的方式,稱作前端路由(區別於後端路由);
在 vue 中使用 vue-router
- 導入 vue-router 組件類庫:
<!-- 1. 導入 vue-router 組件類庫 -->
<script src="./lib/vue-router-2.7.0.js"></script>
- 使用 router-link 組件來導航
<!-- 2. 使用 router-link 組件來導航 -->
<router-link to="/login">登錄</router-link>
<router-link to="/register">註冊</router-link>
- 使用 router-view 組件來顯示匹配到的組件
<!-- 3. 使用 router-view 組件來顯示匹配到的組件 -->
<router-view></router-view>
- 創建使用
Vue.extend
創建組件
// 4.1 使用 Vue.extend 來創建登錄組件
var login = Vue.extend({
template: '<h1>登錄組件</h1>'
});
// 4.2 使用 Vue.extend 來創建註冊組件
var register = Vue.extend({
template: '<h1>註冊組件</h1>'
});
- 創建一個路由 router 實例,通過 routers 屬性來定義路由匹配規則
// 5. 創建一個路由 router 實例,通過 routers 屬性來定義路由匹配規則
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
- 使用 router 屬性來使用路由規則
// 6. 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
router: router // 使用 router 屬性來使用路由規則
});
使用tag屬性指定router-link渲染的標籤類型
設置路由重定向
設置路由高亮
設置路由切換動效
在路由規則中定義參數
- 在規則中定義參數:
{ path: '/register/:id', component: register }
- 通過
this.$route.params
來獲取路由中的參數:
var register = Vue.extend({
template: '<h1>註冊組件 --- {{this.$route.params.id}}</h1>'
});
使用 children
屬性實現路由嵌套
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<script>
// 父路由中的組件
const account = Vue.extend({
template: `<div>
這是account組件
<router-link to="/account/login">login</router-link> |
<router-link to="/account/register">register</router-link>
<router-view></router-view>
</div>`
});
// 子路由中的 login 組件
const login = Vue.extend({
template: '<div>登錄組件</div>'
});
// 子路由中的 register 組件
const register = Vue.extend({
template: '<div>註冊組件</div>'
});
// 路由實例
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/account/login' }, // 使用 redirect 實現路由重定向
{
path: '/account',
component: account,
children: [ // 通過 children 數組屬性,來實現路由的嵌套
{ path: 'login', component: login }, // 注意,子路由的開頭位置,不要加 / 路徑符
{ path: 'register', component: register }
]
}
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
account
},
router: router
});
</script>
命名視圖實現經典佈局
- 標籤代碼結構:
<div id="app">
<router-view></router-view>
<div class="content">
<router-view name="a"></router-view>
<router-view name="b"></router-view>
</div>
</div>
- JS代碼:
<script>
var header = Vue.component('header', {
template: '<div class="header">header</div>'
});
var sidebar = Vue.component('sidebar', {
template: '<div class="sidebar">sidebar</div>'
});
var mainbox = Vue.component('mainbox', {
template: '<div class="mainbox">mainbox</div>'
});
// 創建路由對象
var router = new VueRouter({
routes: [
{
path: '/', components: {
default: header,
a: sidebar,
b: mainbox
}
}
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
- CSS 樣式:
<style>
.header {
border: 1px solid red;
}
.content{
display: flex;
}
.sidebar {
flex: 2;
border: 1px solid green;
height: 500px;
}
.mainbox{
flex: 8;
border: 1px solid blue;
height: 500px;
}
</style>
watch
屬性的使用
考慮一個問題:想要實現 名
和 姓
兩個文本框的內容改變,則全名的文本框中的值也跟着改變;(用以前的知識如何實現???)
- 監聽
data
中屬性的改變:
<div id="app">
<input type="text" v-model="firstName"> +
<input type="text" v-model="lastName"> =
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen',
fullName: 'jack - chen'
},
methods: {},
watch: {
'firstName': function (newVal, oldVal) { // 第一個參數是新數據,第二個參數是舊數據
this.fullName = newVal + ' - ' + this.lastName;
},
'lastName': function (newVal, oldVal) {
this.fullName = this.firstName + ' - ' + newVal;
}
}
});
</script>
- 監聽路由對象的改變:
<div id="app">
<router-link to="/login">登錄</router-link>
<router-link to="/register">註冊</router-link>
<router-view></router-view>
</div>
<script>
var login = Vue.extend({
template: '<h1>登錄組件</h1>'
});
var register = Vue.extend({
template: '<h1>註冊組件</h1>'
});
var router = new VueRouter({
routes: [
{ path: "/login", component: login },
{ path: "/register", component: register }
]
});
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: router,
watch: {
'$route': function (newVal, oldVal) {
if (newVal.path === '/login') {
console.log('這是登錄組件');
}
}
}
});
</script>
computed
計算屬性的使用
- 默認只有
getter
的計算屬性:
<div id="app">
<input type="text" v-model="firstName"> +
<input type="text" v-model="lastName"> =
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen'
},
methods: {},
computed: { // 計算屬性; 特點:當計算屬性中所以來的任何一個 data 屬性改變之後,都會重新觸發 本計算屬性 的重新計算,從而更新 fullName 的值
fullName() {
return this.firstName + ' - ' + this.lastName;
}
}
});
</script>
- 定義有
getter
和setter
的計算屬性:
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<!-- 點擊按鈕重新爲 計算屬性 fullName 賦值 -->
<input type="button" value="修改fullName" @click="changeName">
<span>{{fullName}}</span>
</div>
<script>
// 創建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
firstName: 'jack',
lastName: 'chen'
},
methods: {
changeName() {
this.fullName = 'TOM - chen2';
}
},
computed: {
fullName: {
get: function () {
return this.firstName + ' - ' + this.lastName;
},
set: function (newVal) {
var parts = newVal.split(' - ');
this.firstName = parts[0];
this.lastName = parts[1];
}
}
}
});
</script>
watch
、computed
和methods
之間的對比
computed
屬性的結果會被緩存,除非依賴的響應式屬性變化纔會重新計算。主要當作屬性來使用;methods
方法表示一個具體的操作,主要書寫業務邏輯;watch
一個對象,鍵是需要觀察的表達式,值是對應回調函數。主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操作;可以看作是computed
和methods
的結合體;
nrm
的安裝使用
作用:提供了一些最常用的NPM包鏡像地址,能夠讓我們快速的切換安裝包時候的服務器地址;
什麼是鏡像:原來包剛一開始是隻存在於國外的NPM服務器,但是由於網絡原因,經常訪問不到,這時候,我們可以在國內,創建一個和官網完全一樣的NPM服務器,只不過,數據都是從人家那裏拿過來的,除此之外,使用方式完全一樣;
- 運行
npm i nrm -g
全局安裝nrm
包; - 使用
nrm ls
查看當前所有可用的鏡像源地址以及當前所使用的鏡像源地址; - 使用
nrm use npm
或nrm use taobao
切換不同的鏡像源地址;
相關文件
Vue.js - Day5 - Webpack
在網頁中會引用哪些常見的靜態資源?
- JS
- .js .jsx .coffee .ts(TypeScript 類 C# 語言)
- CSS
- .css .less .sass .scss
- Images
- .jpg .png .gif .bmp .svg
- 字體文件(Fonts)
- .svg .ttf .eot .woff .woff2
- 模板文件
- .ejs .jade .vue【這是在webpack中定義組件的方式,推薦這麼用】
網頁中引入的靜態資源多了以後有什麼問題???
- 網頁加載速度慢, 因爲 我們要發起很多的二次請求;
- 要處理錯綜複雜的依賴關係
如何解決上述兩個問題
- 合併、壓縮、精靈圖、圖片的Base64編碼
- 可以使用之前學過的requireJS、也可以使用webpack可以解決各個包之間的複雜依賴關係;
什麼是webpack?
webpack 是前端的一個項目構建工具,它是基於 Node.js 開發出來的一個前端工具;
如何完美實現上述的2種解決方案
- 使用Gulp, 是基於 task 任務的;
- 使用Webpack, 是基於整個項目進行構建的;
- 藉助於webpack這個前端自動化構建工具,可以完美實現資源的合併、打包、壓縮、混淆等諸多功能。
- 根據官網的圖片介紹webpack打包的過程
- webpack官網
webpack安裝的兩種方式
- 運行
npm i webpack -g
全局安裝webpack,這樣就能在全局使用webpack的命令 - 在項目根目錄中運行
npm i webpack --save-dev
安裝到項目依賴中
初步使用webpack打包構建列表隔行變色案例
- 運行
npm init
初始化項目,使用npm管理項目中的依賴包 - 創建項目基本的目錄結構
- 使用
cnpm i jquery --save
安裝jquery類庫 - 創建
main.js
並書寫各行變色的代碼邏輯:
// 導入jquery類庫
import $ from 'jquery'
// 設置偶數行背景色,索引從0開始,0是偶數
$('#list li:even').css('backgroundColor','lightblue');
// 設置奇數行背景色
$('#list li:odd').css('backgroundColor','pink');
- 直接在頁面上引用
main.js
會報錯,因爲瀏覽器不認識import
這種高級的JS語法,需要使用webpack進行處理,webpack默認會把這種高級的語法轉換爲低級的瀏覽器能識別的語法; - 運行
webpack 入口文件路徑 輸出文件路徑
對main.js
進行處理:
webpack src/js/main.js dist/bundle.js
使用webpack的配置文件簡化打包時候的命令
- 在項目根目錄中創建
webpack.config.js
- 由於運行webpack命令的時候,webpack需要指定入口文件和輸出文件的路徑,所以,我們需要在
webpack.config.js
中配置這兩個路徑:
// 導入處理路徑的模塊
var path = require('path');
// 導出一個配置對象,將來webpack在啓動的時候,會默認來查找webpack.config.js,並讀取這個文件中導出的配置對象,來進行打包處理
module.exports = {
entry: path.resolve(__dirname, 'src/js/main.js'), // 項目入口文件
output: { // 配置輸出選項
path: path.resolve(__dirname, 'dist'), // 配置輸出的路徑
filename: 'bundle.js' // 配置輸出的文件名
}
}
實現webpack的實時打包構建
- 由於每次重新修改代碼之後,都需要手動運行webpack打包的命令,比較麻煩,所以使用
webpack-dev-server
來實現代碼實時打包編譯,當修改代碼之後,會自動進行打包構建。 - 運行
cnpm i webpack-dev-server --save-dev
安裝到開發依賴 - 安裝完成之後,在命令行直接運行
webpack-dev-server
來進行打包,發現報錯,此時需要藉助於package.json
文件中的指令,來進行運行webpack-dev-server
命令,在scripts
節點下新增"dev": "webpack-dev-server"
指令,發現可以進行實時打包,但是dist目錄下並沒有生成bundle.js
文件,這是因爲webpack-dev-server
將打包好的文件放在了內存中
- 把
bundle.js
放在內存中的好處是:由於需要實時打包編譯,所以放在內存中速度會非常快 - 這個時候訪問webpack-dev-server啓動的
http://localhost:8080/
網站,發現是一個文件夾的面板,需要點擊到src目錄下,才能打開我們的index首頁,此時引用不到bundle.js文件,需要修改index.html中script的src屬性爲:<script src="../bundle.js"></script>
- 爲了能在訪問
http://localhost:8080/
的時候直接訪問到index首頁,可以使用--contentBase src
指令來修改dev指令,指定啓動的根目錄:
"dev": "webpack-dev-server --contentBase src"
同時修改index頁面中script的src屬性爲<script src="bundle.js"></script>
使用html-webpack-plugin
插件配置啓動頁面
由於使用--contentBase
指令的過程比較繁瑣,需要指定啓動的目錄,同時還需要修改index.html中script標籤的src屬性,所以推薦大家使用html-webpack-plugin
插件配置啓動頁面.
- 運行
cnpm i html-webpack-plugin --save-dev
安裝到開發依賴 - 修改
webpack.config.js
配置文件如下:
// 導入處理路徑的模塊
var path = require('path');
// 導入自動生成HTMl文件的插件
var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, 'src/js/main.js'), // 項目入口文件
output: { // 配置輸出選項
path: path.resolve(__dirname, 'dist'), // 配置輸出的路徑
filename: 'bundle.js' // 配置輸出的文件名
},
plugins:[ // 添加plugins節點配置插件
new htmlWebpackPlugin({
template:path.resolve(__dirname, 'src/index.html'),//模板路徑
filename:'index.html'//自動生成的HTML文件的名稱
})
]
}
- 修改
package.json
中script
節點中的dev指令如下:
"dev": "webpack-dev-server"
- 將index.html中script標籤註釋掉,因爲
html-webpack-plugin
插件會自動把bundle.js注入到index.html頁面中!
實現自動打開瀏覽器、熱更新和配置瀏覽器的默認端口號
注意:熱更新在JS中表現的不明顯,可以從一會兒要講到的CSS身上進行介紹說明!
方式1:
- 修改
package.json
的script節點如下,其中--open
表示自動打開瀏覽器,--port 4321
表示打開的端口號爲4321,--hot
表示啓用瀏覽器熱更新:
"dev": "webpack-dev-server --hot --port 4321 --open"
方式2:
- 修改
webpack.config.js
文件,新增devServer
節點如下:
devServer:{
hot:true,
open:true,
port:4321
}
- 在頭部引入
webpack
模塊:
var webpack = require('webpack');
- 在
plugins
節點下新增:
new webpack.HotModuleReplacementPlugin()
使用webpack打包css文件
- 運行
cnpm i style-loader css-loader --save-dev
- 修改
webpack.config.js
這個配置文件:
module: { // 用來配置第三方loader模塊的
rules: [ // 文件的匹配規則
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }//處理css文件的規則
]
}
- 注意:
use
表示使用哪些模塊來處理test
所匹配到的文件;use
中相關loader模塊的調用順序是從後向前調用的;
使用webpack打包less文件
- 運行
cnpm i less-loader less -D
- 修改
webpack.config.js
這個配置文件:
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
使用webpack打包sass文件
- 運行
cnpm i sass-loader node-sass --save-dev
- 在
webpack.config.js
中添加處理sass文件的loader模塊:
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
使用webpack處理css中的路徑
- 運行
cnpm i url-loader file-loader --save-dev
- 在
webpack.config.js
中添加處理url路徑的loader模塊:
{ test: /\.(png|jpg|gif)$/, use: 'url-loader' }
- 可以通過
limit
指定進行base64編碼的圖片大小;只有小於指定字節(byte)的圖片纔會進行base64編碼:
{ test: /\.(png|jpg|gif)$/, use: 'url-loader?limit=43960' },
使用babel處理高級JS語法
- 運行
cnpm i babel-core babel-loader babel-plugin-transform-runtime --save-dev
安裝babel的相關loader包 - 運行
cnpm i babel-preset-es2015 babel-preset-stage-0 --save-dev
安裝babel轉換的語法 - 在
webpack.config.js
中添加相關loader模塊,其中需要注意的是,一定要把node_modules
文件夾添加到排除項:
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
- 在項目根目錄中添加
.babelrc
文件,並修改這個配置文件如下:
{
"presets":["es2015", "stage-0"],
"plugins":["transform-runtime"]
}
- 注意:語法插件
babel-preset-es2015
可以更新爲babel-preset-env
,它包含了所有的ES相關的語法;
相關文章
babel-preset-env:你需要的唯一Babel插件
Runtime transform 運行時編譯es6
Vue.js - day6
注意:
有時候使用npm i node-sass -D
裝不上,這時候,就必須使用 cnpm i node-sass -D
在普通頁面中使用render函數渲染組件
在webpack中配置.vue組件頁面的解析
-
運行
cnpm i vue -S
將vue安裝爲運行依賴; -
運行
cnpm i vue-loader vue-template-compiler -D
將解析轉換vue的包安裝爲開發依賴; -
運行
cnpm i style-loader css-loader -D
將解析轉換CSS的包安裝爲開發依賴,因爲.vue文件中會寫CSS樣式; -
在
webpack.config.js
中,添加如下module
規則:
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
{ test: /\.vue$/, use: 'vue-loader' }
]
}
- 創建
App.js
組件頁面:
<template>
<!-- 注意:在 .vue 的組件中,template 中必須有且只有唯一的根元素進行包裹,一般都用 div 當作唯一的根元素 -->
<div>
<h1>這是APP組件 - {{msg}}</h1>
<h3>我是h3</h3>
</div>
</template>
<script>
// 注意:在 .vue 的組件中,通過 script 標籤來定義組件的行爲,需要使用 ES6 中提供的 export default 方式,導出一個vue實例對象
export default {
data() {
return {
msg: 'OK'
}
}
}
</script>
<style scoped>
h1 {
color: red;
}
</style>
- 創建
main.js
入口文件:
// 導入 Vue 組件
import Vue from 'vue'
// 導入 App組件
import App from './components/App.vue'
// 創建一個 Vue 實例,使用 render 函數,渲染指定的組件
var vm = new Vue({
el: '#app',
render: c => c(App)
});
在使用webpack構建的Vue項目中使用模板對象?
- 在
webpack.config.js
中添加resolve
屬性:
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
ES6中語法使用總結
-
使用
export default
和export
導出模塊中的成員; 對應ES5中的module.exports
和export
-
使用
import ** from **
和import '路徑'
還有import {a, b} from '模塊標識'
導入其他模塊 -
使用箭頭函數:
(a, b)=> { return a-b; }
在vue組件頁面中,集成vue-router路由模塊
- 導入路由模塊:
import VueRouter from 'vue-router'
- 安裝路由模塊:
Vue.use(VueRouter);
- 導入需要展示的組件:
import login from './components/account/login.vue'
import register from './components/account/register.vue'
- 創建路由對象:
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
- 將路由對象,掛載到 Vue 實例上:
var vm = new Vue({
el: '#app',
// render: c => { return c(App) }
render(c) {
return c(App);
},
router // 將路由對象,掛載到 Vue 實例上
});
- 改造App.vue組件,在 template 中,添加
router-link
和router-view
:
<router-link to="/login">登錄</router-link>
<router-link to="/register">註冊</router-link>
<router-view></router-view>
組件中的css作用域問題
抽離路由爲單獨的模塊
使用 餓了麼的 MintUI 組件
- 導入所有MintUI組件:
import MintUI from 'mint-ui'
- 導入樣式表:
import 'mint-ui/lib/style.css'
- 在 vue 中使用 MintUI:
Vue.use(MintUI)
- 使用的例子:
<mt-button type="primary" size="large">primary</mt-button>
使用 MUI 組件
- 導入 MUI 的樣式表:
import '../lib/mui/css/mui.min.css'
- 在
webpack.config.js
中添加新的loader規則:
{ test: /\.(png|jpg|gif|ttf)$/, use: 'url-loader' }
- 根據官方提供的文檔和example,嘗試使用相關的組件
將項目源碼託管到oschina中
-
點擊頭像 -> 修改資料 -> SSH公鑰 如何生成SSH公鑰
-
創建自己的空倉儲,使用
git config --global user.name "用戶名"
和git config --global user.email ***@**.com
來全局配置提交時用戶的名稱和郵箱 -
使用
git init
在本地初始化項目 -
使用
touch README.md
和touch .gitignore
來創建項目的說明文件和忽略文件; -
使用
git add .
將所有文件託管到 git 中 -
使用
git commit -m "init project"
將項目進行本地提交 -
使用
git remote add origin 倉儲地址
將本地項目和遠程倉儲連接,並使用origin最爲遠程倉儲的別名 -
使用
git push -u origin master
將本地代碼push到倉儲中
App.vue 組件的基本設置
-
頭部的固定導航欄使用
Mint-UI
的Header
組件; -
底部的頁籤使用
mui
的tabbar
; -
購物車的圖標,使用
icons-extra
中的mui-icon-extra mui-icon-extra-cart
,同時,應該把其依賴的字體圖標文件mui-icons-extra.ttf
,複製到fonts
目錄下! -
將底部的頁籤,改造成
router-link
來實現單頁面的切換; -
Tab Bar 路由激活時候設置高亮的兩種方式:
- 全局設置樣式如下:
.router-link-active{
color:#007aff !important;
}
- 或者在
new VueRouter
的時候,通過linkActiveClass
來指定高亮的類:
// 創建路由對象
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' }
],
linkActiveClass: 'mui-active'
});
實現 tabbar 頁籤不同組件頁面的切換
-
將 tabbar 改造成
router-link
形式,並指定每個連接的to
屬性; -
在入口文件中導入需要展示的組件,並創建路由對象:
// 導入需要展示的組件
import Home from './components/home/home.vue'
import Member from './components/member/member.vue'
import Shopcar from './components/shopcar/shopcar.vue'
import Search from './components/search/search.vue'
// 創建路由對象
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/member', component: Member },
{ path: '/shopcar', component: Shopcar },
{ path: '/search', component: Search }
],
linkActiveClass: 'mui-active'
});
使用 mt-swipe 輪播圖組件
- 假數據:
lunbo: [
'http://www.itcast.cn/images/slidead/BEIJING/2017440109442800.jpg',
'http://www.itcast.cn/images/slidead/BEIJING/2017511009514700.jpg',
'http://www.itcast.cn/images/slidead/BEIJING/2017421414422600.jpg'
]
- 引入輪播圖組件:
<!-- Mint-UI 輪播圖組件 -->
<div class="home-swipe">
<mt-swipe :auto="4000">
<mt-swipe-item v-for="(item, i) in lunbo" :key="i">
<img :src="item" alt="">
</mt-swipe-item>
</mt-swipe>
</div>
</div>
在.vue
組件中使用vue-resource
獲取數據
-
運行
cnpm i vue-resource -S
安裝模塊 -
導入 vue-resource 組件
import VueResource from 'vue-resource'
- 在vue中使用 vue-resource 組件
Vue.use(VueResource);
day7
使用mui的tab-top-webview-main
完成分類滑動欄
兼容問題
- 和 App.vue 中的
router-link
身上的類名mui-tab-item
存在兼容性問題,導致tab欄失效,可以把mui-tab-item
改名爲mui-tab-item1
,並複製相關的類樣式,來解決這個問題;
.mui-bar-tab .mui-tab-item1.mui-active {
color: #007aff;
}
.mui-bar-tab .mui-tab-item1 {
display: table-cell;
overflow: hidden;
width: 1%;
height: 50px;
text-align: center;
vertical-align: middle;
white-space: nowrap;
text-overflow: ellipsis;
color: #929292;
}
.mui-bar-tab .mui-tab-item1 .mui-icon {
top: 3px;
width: 24px;
height: 24px;
padding-top: 0;
padding-bottom: 0;
}
.mui-bar-tab .mui-tab-item1 .mui-icon~.mui-tab-label {
font-size: 11px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
tab-top-webview-main
組件第一次顯示到頁面中的時候,無法被滑動的解決方案:
- 先導入 mui 的JS文件:
import mui from '../../../lib/mui/js/mui.min.js'
- 在 組件的
mounted
事件鉤子中,註冊 mui 的滾動事件:
mounted() {
// 需要在組件的 mounted 事件鉤子中,註冊 mui 的 scroll 滾動事件
mui('.mui-scroll-wrapper').scroll({
deceleration: 0.0005 //flick 減速係數,係數越大,滾動速度越慢,滾動距離越小,默認值0.0006
});
}
- 滑動的時候報警告:
Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
解決方法,可以加上* { touch-action: none; } 這句樣式去掉。
原因:(是chrome爲了提高頁面的滑動流暢度而新折騰出來的一個東西) http://www.cnblogs.com/pearl07/p/6589114.html
https://developer.mozilla.org/zh-CN/docs/Web/CSS/touch-action
移除嚴格模式
babel-plugin-transform-remove-strict-mode
vue-preview
一個Vue集成PhotoSwipe圖片預覽插件
day8
使用mui的tab-top-webview-main
完成分類滑動欄
兼容問題
- 和 App.vue 中的
router-link
身上的類名mui-tab-item
存在兼容性問題,導致tab欄失效,可以把mui-tab-item
改名爲mui-tab-item1
,並複製相關的類樣式,來解決這個問題;
.mui-bar-tab .mui-tab-item1.mui-active {
color: #007aff;
}
.mui-bar-tab .mui-tab-item1 {
display: table-cell;
overflow: hidden;
width: 1%;
height: 50px;
text-align: center;
vertical-align: middle;
white-space: nowrap;
text-overflow: ellipsis;
color: #929292;
}
.mui-bar-tab .mui-tab-item1 .mui-icon {
top: 3px;
width: 24px;
height: 24px;
padding-top: 0;
padding-bottom: 0;
}
.mui-bar-tab .mui-tab-item1 .mui-icon~.mui-tab-label {
font-size: 11px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
tab-top-webview-main
組件第一次顯示到頁面中的時候,無法被滑動的解決方案:
- 先導入 mui 的JS文件:
import mui from '../../../lib/mui/js/mui.min.js'
- 在 組件的
mounted
事件鉤子中,註冊 mui 的滾動事件:
mounted() {
// 需要在組件的 mounted 事件鉤子中,註冊 mui 的 scroll 滾動事件
mui('.mui-scroll-wrapper').scroll({
deceleration: 0.0005 //flick 減速係數,係數越大,滾動速度越慢,滾動距離越小,默認值0.0006
});
}
- 滑動的時候報警告:
Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
解決方法,可以加上* { touch-action: none; } 這句樣式去掉。
原因:(是chrome爲了提高頁面的滑動流暢度而新折騰出來的一個東西) http://www.cnblogs.com/pearl07/p/6589114.html
https://developer.mozilla.org/zh-CN/docs/Web/CSS/touch-action
移除嚴格模式
babel-plugin-transform-remove-strict-mode
vue-preview
一個Vue集成PhotoSwipe圖片預覽插件