什么是Vue.js
- Vue.js是目前最火的一個前端框架,React是最流行的一個前端框架,(React除了開發(fā)網(wǎng)站,還可以開發(fā)手機App,Vue語法也是可以用于手機App開發(fā)的,需要借助于Weex)
- Vue.js是前端的主流框架之一,和Angualr.js、React.js一起,并稱為前端三大主流框架
- Vue.js是一套構(gòu)建用戶界面的框架,**只關(guān)注視圖層++,它不僅易上手,還便于與第三方庫或既有項目整合。(Vue有配套的第三方類庫,可以整合起來做大型項目的開發(fā))
- 前端的主要工作?主要負(fù)責(zé)MVC中的V這一層,蛀牙工作就是和界面打交道。
為什么學(xué)習(xí)流行框架
- 企業(yè)為了提高開發(fā)效率,在企業(yè)中,時間就是效率,效率就是金錢。
- 提高開發(fā)效率的發(fā)展歷程:原生JS -> Jquery之類的類庫 -> 前端模板引擎 -> Angular.js / Vue.js(能夠幫助我們減少不必要的DOM操作;提高渲染效率;雙向數(shù)據(jù)綁定的概念【通過跨年提供的指令,前端程序員只需要關(guān)心數(shù)據(jù)的業(yè)務(wù)邏輯,不在關(guān)心DOM是如何渲染的】)
- 在Vue中,一個核心的概念,就是讓用戶不再操作DOM元素,解放了用戶的雙手,讓程序員可以更多的時候去關(guān)注業(yè)務(wù)邏輯。
- 增強就業(yè)競爭力
框架和庫的區(qū)別
- 框架:是一套完整的解決方案:對項目的侵入性較大,項目如果需要更換框架,則需要重新架構(gòu)整個項目
- 庫(插件):提供某一個小功能,對項目的侵入性較小。如果某個庫無法完成某些需求,可以很容易切換到其他庫實現(xiàn)需求。
Node(后端)中的MVC與前端中的MVVM之間的區(qū)別
MVC是后端的分層開發(fā)概念。M指Model,主要處理數(shù)據(jù);V是視圖層,(前端頁面);C是業(yè)務(wù)邏輯層(路由、用戶登錄注銷)
MVVM是前端視圖層的概念,主要關(guān)注于視圖層分離。也就是說:MVVM把前端的視圖層,分為了三部分Model,View,VM ViewModel
為什么有了MVC還要有MVVM
Vue.js基本代碼和MVVM之間的對應(yīng)關(guān)系
Vue之 基本代碼結(jié)構(gòu) 和插值表達(dá)式、v-cloak
Vue指令之v-tex和v-html
Vue指令之v-bind的三種用法
- 直接使用 指令
v-bind - 使用簡化指令
: - 在綁定的時候,拼接綁定內(nèi)容:
:title="btnTitle + ',這是追加的內(nèi)容'"
Vue指令之v-on和跑馬燈效果
跑馬燈效果
-
HTML結(jié)構(gòu):
<div id="app"> <input type="button" value="快樂" @click="run"> <input type="button" value="我不" @click="stop"> <h4>{{ msg }}</h4> </div>
2.Vue實例
//在vm實例中,如果要獲取data里的數(shù)據(jù)或調(diào)用methods中的方法,
//必須通過 this.數(shù)據(jù)屬性名 或 this.方法名來進(jìn)行訪問,this代表vm實例對象
var vm = new Vue({
el: '#app',
data: {
msg: '快樂的一只小青蛙~',
intervalId: null //在data上定義定時器的Id,開一個定時器就重新定義一遍
},
methods: {
run() {
// 判斷定時器是否為null,是否在靜止?fàn)顟B(tài)點擊的“快樂”按鈕,不是則返回,是則執(zhí)行下列代碼
if(this.intervalId != null) return;
//es6語法,不需要先獲取this再重新賦值
//嵌套函數(shù)內(nèi)部的this與外部的this保持一致
this.intervalId = setInterval( () => {
// 獲取頭部的第一個字符
var start = this.msg.substring(0,1)
// 獲取到后面的所有字符
var end = this.msg.substring(1)
// 重新拼接得到新的字符串,并賦值給 this.msg
this.msg = end + start
//vm實例會監(jiān)聽自己內(nèi)部data中所有數(shù)據(jù)的改變,只要數(shù)據(jù)已發(fā)生編發(fā),就會自動把最新的數(shù)據(jù),
//從data上同步到頁面中去,因此程序員只要關(guān)心數(shù)據(jù)的變化,不需要關(guān)心重新渲染
}, 400)
},
stop() {
clearInterval(this.intervalId)
// 每當(dāng)清除了定時器之后,需要把定時器重新賦值給null
this.intervalId = null
}
}
})
//分析
//1. 給“快樂”按鈕,綁定一個點擊事件
//2. 在按鈕的事件處理函數(shù)中,寫相關(guān)的業(yè)務(wù)邏輯:拿到msg字符串,然后低哦用字符串的
//substring來進(jìn)行字符串的截取操作,把第一個字符截取出來放到最后一個位置即可
//3. 為了實現(xiàn)點擊下按鈕,自動截取的功能,需要把步驟2中國的代碼,放到一個定時器中去。
Vue指令之v-on的縮寫和事件修飾符
事件修飾符:
- .stop 阻止冒泡
- .prevent 阻止默認(rèn)事件
- .capture 添加事件偵聽器時使用事件捕獲模式
- .self 只當(dāng)事件在該元素本身(比如不是子元素)觸發(fā)時觸發(fā)回調(diào)
- .once事件只觸發(fā)一次
Vue指令之v-model和雙向數(shù)據(jù)綁定
簡易計算器案例
- HTML代碼結(jié)構(gòu)
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" @click="calc">
<input type="text" v-model="result">
</div>
-
vue實例
var vm = new Vue({ el: "#app", data: { n1: 0, n2: 0, result: 0, opt: '+' }, methods: { calc () { //1.算數(shù)方法 // switch(this.opt){ // case '+': // this.result = parseInt(this.n1) + parseInt(this.n2) // break; // case '-': // this.result = parseInt(this.n1) - parseInt(this.n2) // break; // case '*': // this.result = parseInt(this.n1) * parseInt(this.n2) // break; // case '/': // this.result = parseInt(this.n1) / parseInt(this.n2) // break; // } //2.投機取巧,正式開發(fā)中,盡量少用 var codeStr = 'parseInt(this.n1)' + this.opt + 'parseInt(this.n2)' this.result = eval(codeStr) } } });
在Vue中 使用樣式
使用class樣式
1.數(shù)組
<h1 :class="['red','thin']">這是一個熟悉的H1</h1>
2.數(shù)組中使用三元表達(dá)式
<h1 :class="['red','thin',isactive?'active':'']">這是一個熟悉的H1</h1>
3.數(shù)組中嵌套對象
<h1 :class="['red','thin',{'active':isactive}]>這是一個熟悉的H1</h1>
4.直接使用對象
<h1 :class="{red:true, italic:true, active:true, thin:true}">這是一個熟悉的H1</h1>
使用內(nèi)聯(lián)樣式
1.直接在元素上通過 :style的形式,書寫樣式對象
<h1 :style="{color:'red', 'font-size': '40px'}">這是一個熟悉的H1</h1>
2.將樣式對象,定義到data中,并直接引用到:style中
- 在data上定義樣式:
data: {
h1StyleObj: {color: 'red', 'font-size': '40px', 'font-weight': '200'}
}
- 在元素中,通過屬性綁定的形式,將樣式對象引用到元素中
<h1: style="h1StyleObj">這是一個熟悉的H1</h1>
3.在:style中通過數(shù)組,引用多個data上的樣式對象
- 在data上定義樣式:
data: {
h1StyleObj1: { color: 'red', 'font-size': '40px', 'font-wight': '200'},
h1StyleObj2: { fontStyle: 'italic' }
}
- 在元素中,通過屬性綁定的形式,將楊思對象應(yīng)用到元素中:
<h1 :style="{h1StyleObj,h2StyleObj2}">這是一個熟悉的H1</h1>
Vue指令之v-for和key屬性
1.迭代數(shù)組
<ul>
<li v-for="{item,i} in list">索引:{{i}} --- 姓名:{{item.name}} --- 年齡:{{item.age}}</li>
</ul>
2.迭代對象中的屬性
<!-- 循環(huán)遍歷對象身上的屬性 -->
<div v-for="{val,key,i} in userInfo>{{val}} --- {{key}} --- {{i}}</div>
3.迭代數(shù)字
<p v-for="i in 10">這是第 {{i}} 個p標(biāo)簽</p>
2.2.0+版本里,當(dāng)在組件中使用 v-for 時,key現(xiàn)在是必須的。
當(dāng) Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認(rèn)用 “就地復(fù)用”策略。如果數(shù)據(jù)項的順序被改變,Vue將不是移動DOM元素來匹配數(shù)據(jù)項的順序,而是簡單復(fù)用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。
為了給Vue 一個提示,以便它能跟蹤每個節(jié)點的身份,從而復(fù)用和重新排序現(xiàn)有元素,你需要為每項提供一個唯一 key 屬性。
Vue指令之v-if和v-show
一般來說,v-if有更高的切換消耗而v-show有更高的初始渲染消耗,因此,如果需要頻繁切換v-show較好,如果在運行時條件不大可能改變v-if較好
Vue.js-Day2
品牌管理案例
添加新品牌
刪除品牌
根據(jù)條件篩選品牌
- 1.x版本中的filterBy指令,在2.x中已經(jīng)被廢除:
[filterBy - 指令]
<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版本中:
Vue調(diào)試工具vue-devtools的安裝步驟和使用
https://chrome.google.com/webstore/search/devtools?hl=zh-CN
過濾器
概念:Vue.js允許自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個地方:sustache 插值和 v-bind 表達(dá)式。過濾器應(yīng)該被添加在JavaScript表達(dá)式的尾部,由“管道”符指示;
私有過濾器
- HTML元素
<td>{{item.ctime | dataforms('yyyy-mmm-dd')}}</td>
-
私有
filters定義方式://定義一個私有的過濾器 var vm2 = new Vue({ el: '#app2', data: { dt: new Date() }, methods: { }, //帶 s ,對象, 定義私有過濾器, 過濾器有兩個條件: [過濾器名稱 和 處理函數(shù)] //過濾器調(diào)用的時候,采用的是就近原則,如果私有過濾器和全局過濾器的名稱一樣,則優(yōu)先調(diào)用私有的 filters: { dataFormat: function(dateStr, pattern = '') { //根據(jù)給定的時間字符串,得到特定的時間 var dt = new Date(dateStr) // yyyy - mm - dd var y = dt.getFullYear() //padStart(maxLength, fillString='')字符填充方法,最大長度為2,不夠則在前面填充0 //padEnd(maxLength, fillString='')同理,不同的是在后面添加 var m = (dt.getMonth() + 1 ).toString().padStart(2,'0') var d = dt.getDate().toString().padStart(2,'0') //先轉(zhuǎn)成小寫 if(pattern.toLowerCase() === 'yyyy-mm-dd') { return `${y}-${m}-$u0z1t8os` }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}-$u0z1t8os ${hh}:${mm}:${ss}~~~~` } } } })
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString='') 或 String.prototype.padEnd(maxLength, fillSting='')來填充字符串;
全局過濾器
//定義一個全局的過濾器, 進(jìn)行時間格式化,被所有的vm實例共用
Vue.filter('dataFormat',function (dateStr, pattern="") {
//根據(jù)給定的時間字符串,得到特定的時間
var dt = new Date(dateStr)
// yyyy - mm - dd, 獲取年月日
var y = dt.getFullYear()
var m = dt.getMonth() + 1
var d = dt.getDate()
// return y + '-' + m +'-' +d //用以下形式代替:
//return `${y}-${m}-$u0z1t8os`
//先轉(zhuǎn)成小寫
//如果 傳遞進(jìn)來的字符串類型 ,轉(zhuǎn)為小寫后,等于yyyy-mm-dd,那么就返回 年-月-日
//否則,就返回 年-月-日 時:分:秒
if(pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-$u0z1t8os`
}else {
//獲取時分秒
var hh = dt.getHours()
var mm = dt.getMinutes()
var ss = dt.getSeconds()
return `${y}-${m}-$u0z1t8os ${hh}:${mm}:${ss}`
}
})
注意:當(dāng)有局部和全局兩個名稱相同的過濾器的時候,會以就近原則進(jìn)行調(diào)用,即:局部過濾器優(yōu)先于全局過濾器被調(diào)用!
鍵盤修飾符以及自定義鍵盤修飾符
1. 1.x中自定義鍵盤修飾符【了解即可】
Vue.directive('on').keyCodes.f2 = 113;
2.x自定義鍵盤修飾符 https://cn.vuejs.org/v2/guide/events.html#%E6%8C%89%E9%94%AE%E7%A0%81
1.1 通過Vue.config.keyCodes.名稱 = 按鍵值來自定義按鍵修飾符的別名:
`Vue.config.keyCodes.f2 = 113;`
1.2 使用自定義的按鍵修飾符
`<input type="text" v-model="name" @keyup.f2="add">`
2.可以直接調(diào)用按鍵值(f2的按鍵值為113)
`<input type="text" v-model="name" @keyup.113="add">`
3.使用系統(tǒng)內(nèi)置的按鍵可以不用定義
`<input type="text" v-model="name" @keyup.enter="add">`
自定義指令 https://cn.vuejs.org/v2/guide/custom-directive.html
- 自定義全局和局部的 自定義指令:
全局
// 注冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當(dāng)被綁定的元素插入到 DOM 中時……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
局部
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}
- 鉤子函數(shù)
https://cn.vuejs.org/v2/guide/custom-directive.html#%E9%92%A9%E5%AD%90%E5%87%BD%E6%95%B0
// 使用 Vue.derective() 自定義全局指令
// 其中:參數(shù)1:指令的名稱,注意,在定義的時候,指令的名稱前面,不需要加 v- 前綴,
// 但是: 在調(diào)用的時候,必須在指令名稱前加上 v- 前綴來進(jìn)行調(diào)用
//參數(shù)2:是一個對象,這個對象身上,有一些指令相關(guān)的函數(shù),這些函數(shù)可以在特定的階段,執(zhí)行相關(guān)的操作
Vue.directive('focus',{
bind:function(el) {//每當(dāng)指令綁定到元素上的時候,就立即執(zhí)行 bind 函數(shù),只執(zhí)行一次
/// 注意: 在每個函數(shù)中,第一個參數(shù)永遠(yuǎn)是 el ,表示被綁定了指令的元素,這個 el 參數(shù),是一個原生的JS對象
// 在元素剛綁定了指令的時候,還沒有插入到 DOM 中去,這時候,調(diào)用 focus 方法沒有作用
// 因為,一個元素,只有插入DOM之后,才能獲取焦點
//el.focus()
},
inserted: function(el) {// inserted 表示元素插入到 DOM 中的時候,會執(zhí)行 inserted 函數(shù),只執(zhí)行一次
el.focus()
// 和 JS 行為有關(guān)的操作,最好在 inserted 中去執(zhí)行,防止 JS 行為不生效
},
updated: function() {// 當(dāng) VNode 更新的時候,會執(zhí)行 updated 函數(shù),可能被觸發(fā)多次
}
})
- 鉤子函數(shù)的參數(shù)
- el:指令所綁定的元素
- binding
- name:指令的名字,不包含
v-前綴 - value:指令的綁定值:例如:
v-my-directive="1 + 1"中,綁定值為2。 - expression:字符串形式的表達(dá)式,例如
v-my-directive="1 + 1"中,表達(dá)式為"1 + 1"。
html:
<input type="text" class="form-control" v-model="keywords" id="search" v-focus v-color="'blue'">
自定義指令:
//自定義設(shè)置字體顏色的指令
Vue.directive('color',{
// 樣式只要通過指令綁定給了元素,不管這個元素有沒有被插入到頁面中去,這個元素肯定有一個內(nèi)聯(lián)樣式
// 將來元素肯定會顯示到頁面上,這時候瀏覽器的渲染引擎必然會解析樣式,應(yīng)用給這個元素
bind:function(el,binding) {
// el.style.color = 'red'
// 和 樣式 相關(guān)的操作,一般都可以在 bind 中定義
el.style.color = binding.value
}
})
- 簡寫函數(shù):在 bind 和 update 時觸發(fā)相同行為,而不關(guān)心其它的鉤子函數(shù)
下面的例子是自定義私有指令和簡寫函數(shù)
directives: { // 自定義私有指令
'fontweight': { // 設(shè)置字體粗細(xì)
bind: function (el,binding) {
el.style.fontWeight = binding.value
}
},
'fontsize': function(el,binding) { //簡寫函數(shù),注意:這個 function 等同于把代碼寫到了 bind 和 update 中去
el.style.fontSize = parseInt(binding.value) + 'px'
}
}
Vue實例的生命周期
- 什么是生命周期:從Vue實例創(chuàng)建、運行、到銷毀期間,總是伴隨著各種各樣的事件,這些事件,統(tǒng)稱為生命周期。
- 生命周期鉤子:就是生命周期事件的別名而已;
- 生命周期鉤子 = 生命周期函數(shù) = 生命周期事件
- 主要的生命周期函數(shù)分類:
- 創(chuàng)建期間的生命周期函數(shù):
- beforeCreate:實例剛在內(nèi)存中被創(chuàng)建出來,此時,還沒有初始化好 data 和 methods 屬性
- created: 實例已經(jīng)在內(nèi)存中創(chuàng)建完成;此時 data 和 methods 已經(jīng)創(chuàng)建完成,此時還沒有開始編譯模板
- beforeMount:此時已經(jīng)完成了模板的編譯,但是還沒有掛載到頁面中
- mounted:此時,已經(jīng)將編譯好的模板,掛載到了頁面指定的容器中顯示
- 運行期間的生命周期函數(shù):
- beforeUpdate:狀態(tài)更新之前執(zhí)行此函數(shù),此時 data 中的狀態(tài) 值是最新的,但是界面上顯示的數(shù)據(jù)還是舊的。因為此時還沒有開始重新渲染 DOM 節(jié)點
- updated:實例更新完畢之后調(diào)用此函數(shù),此時 data 中的狀態(tài)值 和 界面上顯示的數(shù)據(jù),都已經(jīng)完成了更新,界面已經(jīng)被重新渲染好了
- 銷毀期間的生命周期函數(shù):
- beforeDestroy:實例銷毀之前調(diào)用。在這一步,實例仍然完全可用
- destroyed:Vue 實例銷毀后調(diào)用。調(diào)用后,Vue 實例指示的所有東西都會解除綁定,所有的事件監(jiān)聽器會被移除,所有的子實例也會被銷毀。
vue-resource實現(xiàn)get,post,jsonp請求
除了 vue-resource 之外,還可以使用 axios的第三方包實現(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的實現(xiàn)原理
- 由于瀏覽器的安全性限制,不允許AJAX訪問協(xié)議不同、域名不同、端口號不同的數(shù)據(jù)接口,瀏覽器認(rèn)為這種訪問不安全;
- 可以通過動態(tài)創(chuàng)建script標(biāo)簽的形式,把script標(biāo)簽的src屬性,指向數(shù)據(jù)接口的地址,因為script標(biāo)簽不存在跨域限制,這種 數(shù)據(jù)獲取方式,稱作為JSONP(注意:根據(jù)JSON的實現(xiàn)原理,知曉,JSONP只支持GET請求);
- 具體實現(xiàn)過程;
- 先在客戶端定義一個回調(diào)方法,預(yù)定義對數(shù)據(jù)的操作;
- 再把這個回調(diào)方法的名稱,通過URL傳參的形式,提交都服務(wù)器的數(shù)據(jù)接口
- 服務(wù)器數(shù)據(jù)接口組織好要發(fā)送給 客戶端的數(shù)據(jù),再拿著客戶端傳遞過來的回調(diào)方法名稱,拼接出一個調(diào)用這個方法的字符串,發(fā)送給客戶端去解析執(zhí)行;
- 客戶端拿到服務(wù)器返回的字符串之后,當(dāng)作script腳本去解析執(zhí)行,這樣就能夠拿到JSONP的數(shù)據(jù)了;
配置本地數(shù)據(jù)庫和數(shù)據(jù)接口API
- 先解壓安裝
PHPStudy; - 解壓安裝
Navicat這個數(shù)據(jù)庫可視化工具,并激活; - 打開
Navicat工具,新建空白數(shù)據(jù)庫,名為dtcmsdb4; - 雙擊新建的數(shù)據(jù)庫,連接上這個空白數(shù)據(jù)庫,在新建的數(shù)據(jù)庫上
右鍵->運行SQL文件,選擇并執(zhí)行dtcmsdb4.sql這個數(shù)據(jù)庫腳本文件;如果執(zhí)行不報錯,則數(shù)據(jù)庫導(dǎo)入完成; - 進(jìn)入文件夾
vuecms3_nodejsapi內(nèi)部,執(zhí)行npm i安裝所有的依賴項; - 先確保本機安裝 了
nodemon,沒有安裝則運行npm i nodemon -g進(jìn)行全局安裝,安裝完畢后,進(jìn)入到vuecms_nodejsapi目錄 ->src目錄 -> 雙擊運行start.bat - 如果API啟動失敗,請檢查 PHPStudy 中默認(rèn)的用戶名是 root,默認(rèn)的密碼也是 root
品牌管理改造
展示品牌列表
添加品牌數(shù)據(jù)
刪除品牌數(shù)據(jù)
Vue中的動畫
為什么要有動畫:動畫能夠提高用戶的體驗,幫助用戶更好的理解頁面中的功能
使用過渡類名
-
HTML結(jié)構(gòu)
<div id="app> <input type="button" value="動起來" @click="myAnimate"> <!-- 使用 transition 將需要過渡的元素包裹起來 --> <transition name="false"> <div v-show="isshow">動畫</div> </transition> </div> -
VM實例
// 創(chuàng)建 Vue實例,得到 ViewModel var vm = new Vue({ el:'#app', data:{ isshow: false }, methods:{ myAnimate:{ this.isshow = !this.isshow; } } })
Vue.js-Day3
定義Vue組件
什么是組件: 組件的出現(xiàn),就是為了拆分Vue實例的代碼量的,能夠讓我們以不同的組件,來劃分不同的功能模塊,將來我們需要什么樣的功能,就可以去調(diào)用對應(yīng)的組件即可;
組件化和模塊化的不同:
- 模塊化:是從代碼邏輯的角度進(jìn)行劃分的;方便后臺代碼的分層開發(fā),保證每一個功能模塊的職能單一;
- 組件化:是從UI界面進(jìn)行劃分的;方便UI組件的復(fù)用;
全局組件定義的三種方式
-
使用 Vue.extend 配合 Vue.component 方法;
var login = Vue.extend({ template: '<h1>登錄</h1>' }); Vue.component('login',login); -
直接使用 Vue.component 方法:
Vue.component('register',{ template: '<h1>注冊</h1>' }); -
將模板字符串,定義到script標(biāo)簽中:
<script id="tmpl" type="x-template"> <div><a href="#">登錄</a> | <a href="#">注冊</a></div> </script>
同時,需要使用 Vue.component 來定義組件:
Vue.component('account',{
template:'#tmpl'
});
注意:組件中的DOM結(jié)構(gòu),有且只能有唯一的根元素(Root Element)來進(jìn)行包裹
組件中展示數(shù)據(jù)和響應(yīng)事件
- 在組件中 ,
data需要被定義為一個方法。例如:
Vue.js - Day4
父組件向子組件傳值
- 組件實例定義方式,注意:一定要使用
props屬性要定義父組件傳遞過來的數(shù)據(jù)
<script>
// 創(chuàng)建 Vue 實例,得到 ViewModel
var vm = new Vue({
el:'#app',
data: {
msg:'這是父組件的消息'
},
components: {
son: {
template: '<h1>這是子組件 --- {{finfo}}</h1>',
props: [finfo]
}
}
});
</script>
-
使用
v-bind或簡化指令,將數(shù)據(jù)傳遞到子組件中:<div id="app"> <son :finfo="msg"></son> </div>
子組件向父組件傳值
- 原理:父組件將方法的引用,傳遞到子組件內(nèi)部,子組件在內(nèi)部調(diào)用父組件傳遞過來的方法,同時把要發(fā)送給父組件的數(shù)據(jù),在調(diào)用方法的時候當(dāng)作參數(shù)傳遞進(jìn)去;
- 父組件將方法的引用傳遞給子組件,其中,
getMsg是父組件中methods中定義的方法名稱,funo是子組件調(diào)用傳遞過來方法時候的方法名稱
<son @funo="getMsg"></son>
- 子組件內(nèi)部通過
this.$emit(‘方法名',要傳遞的數(shù)據(jù))方式,來調(diào)用父組件中的方法,同時把數(shù)據(jù)傳遞給父組件使用
<div id="app">
<!-- 引用父組件 -->
<son @funo="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('funo,'OK'); // 調(diào)用父組件傳遞過來的方法,同時把數(shù)據(jù)傳遞出去
}
}
});
//創(chuàng)建 Vue 實例,得到 ViewModel
var vm = new Vue({
el: "#app",
data: {},
methods: {
getMsg(val){ //子組件中,通過 this.$emit() 實際調(diào)用的方法,在此進(jìn)行定義
alert(val);
}
}
});
</script>
評論列表案例
目標(biāo):主要練習(xí)父子組件之間傳值
使用this.$refs來獲取元素和組件
<div id="app">
<div>
<input type="button" value="獲取元素內(nèi)容" @click="getElemrnt" />
<!-- 使用 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: '子組件'
}
}
});
//創(chuàng)建Vue實例,得到ViewModel
var vm = new Vuew({
el: "#app",
data: {},
methods: {
getElement() {
// 通過 this.$refs 來獲取元素
console.log(this.$refs.myh1.innerText);
// 通過 this.$refs 來獲取組件
console.log(this.$refs.mycom.name);
}
}
});
</script>
什么是路由
后端路由:對于普通的網(wǎng)站,所有的超鏈接都是URL地址,所有的URL地址都對應(yīng)服務(wù)器上對應(yīng)的資源;
前端路由:對于單頁面應(yīng)用程序來說,主要通過URL中的hash(#號),來實現(xiàn)不同頁面之間的切換,同時,hash有一個特點:HTTP請求中不會包含hash相關(guān)內(nèi)容;所以,單頁面程序中的頁面跳轉(zhuǎn)主要用hash實現(xiàn);
在單頁面應(yīng)用程序中,這種通過hash改變來切換頁面的方式,稱作前端路由(區(qū)別于后端路由);
在 vue 中使用 vue-router
-
導(dǎo)入 vue-router 組件類庫:
<!-- 1. 導(dǎo)入 vue-router 組件類庫 --> <script src="./lib/vue-router-2.7.0.js></script> -
使用 router-linx 組件來導(dǎo)航
<!-- 2. 使用 router-link 組件來導(dǎo)航 --> <router-link to="/login">登錄<、router-link> <router-link to="/register">注冊<、router-link> -
使用 touter-view 組件來顯示匹配到的組件
<!-- 3. 使用 touter-view 組件來顯示匹配到的組件 --> <router-view></router-view> -
創(chuàng)建使用
Vue.extend創(chuàng)建組件// 4.1 使用`Vue.extend`來創(chuàng)建登錄組件 var login = Vue.extend({ template:'<h1>登錄組件</h1>' }); // 4.2 使用`Vue.extend`來創(chuàng)建注冊組件 var register = Vue.extend({ template:'<h1>注冊組件</h1>' }) -
創(chuàng)建一個路由 router 實例,通過 router 屬性來定義路由匹配規(guī)則
// 5. 創(chuàng)建一個路由 router 實例,通過 router 屬性來定義路由匹配規(guī)則 var router = new VueRouter({ router: { { path: '/login',component: login }, { path: '/register',component: register } } }); -
使用 router 屬性來使用路由規(guī)則
// 6. 創(chuàng)建vue實例,得到ViewModel var vm = new Vue({ el:'#app', router: router // 使用router屬性來使用路由規(guī)則 });
使用tag屬性指定router-link渲染的標(biāo)簽類型
<!-- router-link 默認(rèn)渲染為一個 a 標(biāo)簽 -->
<!-- tag 屬性指定 router-link 渲染為 什么元素 -->
<!-- 不管渲染為什么元素,都是可點擊的元素 -->
<router-link to="/login" tag="span">登錄</router-link>
<router-link to="/register">注冊</router-link>
設(shè)置路由重定向
// 2. 創(chuàng)建一個路由對象,當(dāng)導(dǎo)入 vue-router 包之后,在 winodow 全局對象中,就有了一個 路由的構(gòu)造函數(shù):VueRouter
// 在 new 路由對象的時候,可以為構(gòu)造函數(shù),傳遞一個配置對象
var routerObj = new VueRouter({
// route //這個配置對象中的 route 表示 【路由匹配規(guī)則】 的意思
routes: [ // 路由匹配規(guī)則
//每個路由規(guī)則,都是一個對象,這個規(guī)則對象身上,有兩個必須的屬性:
// 屬性1 是 path,表示監(jiān)聽哪個路由鏈接地址
// 屬性2 是 component,表示如果路由前面匹配到的 path,則展示 component 屬性對應(yīng)的那個組件
// 注意:component 的屬性值,必須是一個 組件模板對象,不能是 組件的引用名稱('login')
{ path: '/', redirect: '/login'}, //如果請求的是默認(rèn)路徑,則重定向到 login 組件中
{ path: '/login', component: login},
{ path: '/register', component: register}
],
linkActiveClass: 'myactive' // 為路由高亮指定類名,高亮?xí)r使用 .myactive 樣式,不會使用默認(rèn)的 .router-link-active 樣式
})
設(shè)置路由高亮
方式一:使用vue提供的.router-link-active 進(jìn)行定義
/* 實現(xiàn)路由高亮 */
.router-link-active {
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
}
方式二:為路由對象linkActiveClass重新設(shè)置一個自定義類名,這個類名可以是bootstrap的類名也可以是自定義的
linkActiveClass: 'myactive'
.myactive {
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
background-color: brown;
設(shè)置路由切換動效
<!-- 這是 vue-router 提供的元素,專門用來當(dāng)做占位符的,將來,路由規(guī)則匹配到的組件,就會展示到這個 router-view 中去 -->
<transition mode="out-in"> <!-- 添加動畫效果 -->
<router-view></router-view>
</transitio
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
在路由規(guī)則中定義參數(shù)
方式一:
-
在規(guī)則中定義參數(shù):
{ path: 'register/:id/:name', component: register } -
在路由中傳遞參數(shù):(12、zhangsan 分別對應(yīng)規(guī)則中的id、name)
<router-link to="/login/12/zhangsan">注冊</router-link> -
通過
this.$router.params來獲取路由中的參數(shù):(this可省略)var register = Vue.extend({ template: '<h1>注冊組件 --- {{ this.$router.params.id --- {{ this.$router.params.name }}</h1>' });
方式二:
-
直接在路由中傳遞參數(shù)
<!-- 如果在路由中,使用 查詢字符串,給路由傳參,則不需要修改路由規(guī)則的 path 屬性 --> <router-link to="/login?id=10&name=zhangsan">登錄</router-link> -
通過
this.$router.query來獲取路由中的參數(shù):var login = { template: '<h1>登錄 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>', data() { return { msg: '123' } }, created() { // 組件的生命周期鉤子函數(shù) console.log(this.$route) console.log(this.$route.query.id) } }
使用children屬性實現(xiàn)路由嵌套
<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 實現(xiàn)路由重定向
{
path: '/account',
component: account,
children: [
// 通過 children 數(shù)組屬性,來實現(xiàn)路由的嵌套
{ path: 'login', component: login },//注意,子路由的開頭位置,不需要加 / 路徑符
{ path: 'register', component: register }
]
}
]
});
var vm = new Vue({
el : '#app',
data : { },
methods : { },
components: {
account
},
router: router
});
</script>
命名視圖實現(xiàn)經(jīng)典布局
-
標(biāo)簽代碼結(jié)構(gòu):
<div id="app"> <router-view></router-view> <div class="container"> <!-- name 屬性指定要放的組件 --> <router-view name="left"></router-view> <router-view name="main"></router-view> </div> </div> -
JS代碼
<script> var header = { template: '<h1 class="header">Header頭部</h1>' } var leftBox = { template: '<h1 class="left">Left側(cè)邊欄區(qū)域</h1>' } var mainBox = { template: '<h1 class="main">mainBox主體區(qū)域</h1>' } // 創(chuàng)建路由對象 var router = new VueRouter({ routes: [ // { path: '/', component: header }, // { path: '/left', component: leftBox }, // { path: '/main', component: mainBox }, { path: '/', components: { 'default': header, 'left': leftBox, 'main': mainBox } }, ] }) var vm = new Vue({ el : '#app', data : { }, methods : { }, router }); </script> -
CSS代碼:
<style> html,body { margin: 0; padding: 0; } .header { height: 80px; background-color: orange; } h1 { margin: 0; padding: 0; font-size: 16px; } .container { display: flex; height: 600px; } .left { background-color: lightgreen; flex: 2; } .main { background-color: lightpink; flex: 8; } </style>
watch屬性的使用
html結(jié)構(gòu)
<div id="app">
<input type="text" v-model="firstname"> +
<input type="text" v-model="lastname"> =
<input type="text" v-model="fullname">
</div>
JS代碼
<script>
var vm = new Vue({
el : '#app',
data : {
firstname: '',
lastname: '',
fullname: ''
},
methods : { },
watch: {
// 使用這個屬性可以監(jiān)視 data 中指定數(shù)據(jù)的變化,然后觸發(fā) watch 中對應(yīng)的 function 處理函數(shù)
// 監(jiān)視 firstname 的變化,改變了則調(diào)用 function 函數(shù),如果first-name(帶橫線),需要加上引號
'firstname': function(newVal, oldVal) {
// console.log('監(jiān)視到了 firstname 的變化')
// this.fullname = this.firstname + '-' + this.lastname
// console.log(newVal + '---' + oldVal)
this.fullname = newVal + '-' + this.lastname
},
'lastname': function(newVal) {
this.fullname = this.firstname + '-' + newVal
}
}
});
</script>
使用watch監(jiān)視路由地址的改變
html結(jié)構(gòu)
<div id="app">
<!-- 6.鏈接 -->
<router-link to="/login">登錄</router-link>
<router-link to="/register">注冊</router-link>
<!-- 5.容器 -->
<router-view></router-view>
</div>
JS代碼
<script>
// 2.創(chuàng)建子組件
var login = {
template: '<h1>登錄組件</h1>'
}
var register = {
template: '<h1>注冊組件</h1>'
}
// 3.創(chuàng)建一個路由對象
var router = new VueRouter({
routes: [ //路由規(guī)則數(shù)組
{ path: '/', redirect: '/login' },// 默認(rèn)路徑重定向
{ path: '/login', component: login},
{ path: '/register', component: register}
],
linkActiveClass: 'myactive' // 激活相關(guān)的類
})
var vm = new Vue({
el : '#app',
data : { },
methods : { },
// 4. 掛載路由
router,
watch: {
// this.$route.path 獲取路由
'$route.path': function(newVal,oldVal) {
console.log( newVal + '---' + oldVal )
if ( newVal === '/login') {
console.log('歡迎進(jìn)入登錄頁面')
} else if ( newVal === '/register') {
console.log('歡迎進(jìn)入注冊頁面')
}
}
}
});
</script>
computed計算屬性的使用
html結(jié)構(gòu)
<div id="app">
<input type="text" v-model="firstname"> +
<input type="text" v-model="lastname"> =
<input type="text" v-model="fullname">
<p>{{ fullname }}</p>
<p>{{ fullname }}</p>
<p>{{ fullname }}</p>
</div>
JS代碼
<script>
var vm = new Vue({
el : '#app',
data : {
firstname: '',
lastname: ''
},
methods : { },
computed: {
// 在 computed 中,可以定義一些屬性,這些屬性叫做【計算屬性】,
//本質(zhì)就是一個方法,只不過在使用這些計算屬性的時候,
//是把他們的 名稱直接當(dāng)做 屬性來使用,并不會把計算屬性當(dāng)做方法去調(diào)用。
// 1.注意:計算屬性,在引用的時候,一定不要加()調(diào)用 ,直接把它當(dāng)做普通屬性去使用
// 2.注意:只要計算屬性這個 function 內(nèi)部所用到的 data 中的數(shù)據(jù)發(fā)生了變化,就會立即重新計算這個計算屬性的值
// 意思是 fullname 永遠(yuǎn)跟隨 firstname 和 lastname 的變化而變化
// 3.注意:計算屬性的求值結(jié)果,會被緩存起來,方便下次調(diào)用,如果 計算屬性方法中,所有的數(shù)據(jù)都沒有發(fā)生變化,就不會重新對計算屬性求值
// 'fullname': function() {
// console.log('ok')
// return this.firstname + '-' + this.lastname
// }
fullname: {
get:function() {
console.log('ok')
return this.firstname + '-' + this.lastname
},
set:function() {}
}
}
});
</script>
watch、computed、methods之間的對比
-
computed屬性的結(jié)果會被緩存,除非依賴的響應(yīng)式屬性變化才會重新計算,主要當(dāng)作屬性來使用; -
methods方法表示一個具體的操作,主要書寫業(yè)務(wù)邏輯; -
watch一個對象,鍵是需要觀察的表達(dá)式,值是對應(yīng)回調(diào)函數(shù),主要用來監(jiān)聽某些特定數(shù)據(jù)的變化,從而進(jìn)行某些具體的業(yè)務(wù)邏輯操作,可以看作是computed和methods的結(jié)合體;
nrm的安裝使用
作用:提供了一些最常用的NPM包鏡像地址,能夠讓我們快速的切換安裝包時候的服務(wù)器地址;
什么是鏡像:原來包剛一開始是只存在于國外的NPM服務(wù)器,但是由于網(wǎng)絡(luò)原因,經(jīng)常訪問不到,這時候,我們可以在國內(nèi),創(chuàng)建一個和官網(wǎng)完全一樣的NPM服務(wù)器,只不過,數(shù)據(jù)都是從人家那里拿過來的,除此之外,使用方式完全一樣。
- 運行
npm i nrm -g全局安裝nrm包; - 使用
nrm ls查看當(dāng)前所有可用的鏡像源地址以及當(dāng)前所使用的鏡像源地址; - 使用
nrm use npm或nrm use taobao切換不同的鏡像源地址;
注意:nrm只是單純提供了幾個常用的下載包的URL地址,并能夠讓我們在這幾個地址之間,很方便的進(jìn)行切換,但是,我們每次裝包的時候,使用的裝包工具都是
npm
相關(guān)文件
Vue.js - Day5 - Webpack
在網(wǎng)頁中會引用哪些常見的靜態(tài)資源?
- 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中定義組件的方式,推薦]
網(wǎng)頁中引入的靜態(tài)資源多了以后有什么問題?
- 網(wǎng)頁加載速度慢,因為我們要發(fā)起很多的二次請求;
- 要處理錯綜復(fù)雜的依賴關(guān)系
如何解決上述兩個問題
- 合并、壓縮、精靈圖、小圖片的Base64編碼
- 可以使用requireJS。也可以使用webpack,可以解決各個包之間的復(fù)雜依賴關(guān)系
什么是webpack
webpack 是前端的一個項目構(gòu)建工具,它是基于node.js開發(fā)出來的一個前端工具,因此要使用webpack必須先安裝node
如何完美實現(xiàn)上述的2種解決方案
- 使用Gulp,是基于task任務(wù)的;
- 使用Webpack,是基于整個項目進(jìn)行構(gòu)建的;
- 借助于webpack這個前端自動化構(gòu)建工具,可以完美實現(xiàn)資源的合并、打包、壓縮、混淆等諸多功能。
- 根據(jù)官網(wǎng)的圖片介紹webpack打包過程
- webpack官網(wǎng)
webpack 安裝的兩種方式
- 運行
npm i webpack -g全局安裝webpack,這樣就能在全局使用webpack的命令 - 在項目根目錄中運行
npm i webpack --save-dev安裝到項目依賴中
初步使用webpack打包構(gòu)建列表隔行變色案例
- 運行
npm init初始化項目,使用npm管理項目中的依賴包
VScode快捷鍵ctrl + · 打開終端,注意那個點是鍵盤上 esc 下面的那個;運行npm init -y初始化,初始化完成后可以想見項目目錄多了package.json文件
E:\Vue_Project\vue-study\day5\webpack-study> npm init -y
Wrote to E:\Vue_Project\vue-study\day5\webpack-study\package.json:
{
"name": "webpack-study",
"version": "1.0.
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
- 創(chuàng)建項目基本的目錄結(jié)構(gòu)
- 使用
cnpm i jquery --save安裝jquery類庫
運行npm i jquery -S安裝jquery
E:\Vue_Project\vue-study\day5\webpack-study> npm i jquery -S
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN webpack-study@1.0.0 No description
npm WARN webpack-study@1.0.0 No repository field.
+ jquery@3.4.1
added 1 package from 1 contributor and audited 1 package in 2.161s
found 0 vulnerabilities
-
創(chuàng)建
main.js并書寫各行變色的代碼邏輯:// 導(dǎo)入jquery類庫 import $ from 'jquery' // 設(shè)置偶數(shù)行背景色,索引從0開始,0是偶數(shù) $('#list li:even').css('backgroundColor','lightblue'); // 設(shè)置奇數(shù)行背景色 $('#list li:odd').css('backgroundColor','pink'); 直接在頁面上引用
main.js會報錯,因為瀏覽器不認(rèn)識import這種高級的JS語法。需要使用webpack進(jìn)行處理,webpack默認(rèn)會把這種高級的語法轉(zhuǎn)換為低級的瀏覽器能識別的語法;
運行webpack 入口文件路徑 輸出文件路徑對main.js進(jìn)行處理:
webpack src/js/main.js dist/bundle.js
注意:如果webpack版本過高,上述語句會報錯,需要用
webpack .\src\main.js -o .\dist\bundle.js來打包,詳情webpack 打包報錯:Can't resolve '.\dist\bundle.js' in 'E:\vivian....'
- 由于每次修改main.js文件都需要重新使用
webpack src/js/main.js dist/bundle.js進(jìn)行打包,累贅且麻煩,因此在項目根目錄引入配置文件webpack.config.js,聲明要打包的文件路徑和導(dǎo)出的文件路徑,下次項目更改需要重新打包時,運行webpack即可。
webpack.config.js配置文件內(nèi)容:
const path = require('path')
// 這個配置文件,其實就是一個 JS 文件,通過 node 中的模塊操作,向外暴露了一個 配置對象
module.exports = {
mode: 'development',
entry: path.join(__dirname, './src/main.js'), // 入口,表示要使用 webpack 打包那一個文件
output: {
//輸出文件相關(guān)配置
path: path.join(__dirname, './dist'),//指定 打包好的文件,輸出到哪個目錄中去
filename: 'bundle.js' // 指定 輸出文件的名稱
}
}
// 當(dāng)我們在控制臺,直接輸入 webpack 命令執(zhí)行的時候,webpack做了以下幾步:
// 1. 首先,webpack發(fā)現(xiàn)我們并沒有通過命令的形式,給它指定出口和入口
// 2. webpack 就會去 項目的根目錄 中,查找一個叫做'webpack.config.js'的配置文件
// 3. 當(dāng)找到配置文件后,webpack 會去解析執(zhí)行這個 配置文件,當(dāng)解析執(zhí)行完配置文件后,就得到了配置文件中導(dǎo)出的 配置對象
// 4. 當(dāng) webpack 拿到配置對象后,就拿到了配置對象中,指定的 入口 和出口,然后進(jìn)行打包構(gòu)建
再由于每次代碼更改都需要手動重新打包編譯,使用
webpack-dev-server這個工具進(jìn)行偷懶。運行npm i webpack-dev-server -D,把這個工具安裝到項目的本地開發(fā)依賴。webpack-dev-server要求webpack安裝在本地項目下,運行npm i webpack -D安裝。webpack要求webpack-cli安裝在本地項目下,運行npm i webpack-cli -D安裝。-
在
package.json內(nèi),添加dev,{ "name": "webpack-study", "version": "1.0.0", "description": "", "main": "main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server" //添加webpack-dev-server }, 運行
npm run dev使用webpack-dev-server工具。i ?wds?: Project is running at http://localhost:8080/可在終端查看到服務(wù)器端口http://localhost:8080/
i ?wds?: webpack output is served from /可在終端查看到打包的bundle.js的路徑是根目錄下的絕對路徑,可以通過http://localhost:8080/bundle.js訪問到bundle.js。此時引入bundl.js只需寫根目錄的路徑即可<script src="/bundle.js"></script>此時修改代碼只需保存,webpack-dev-server就會實時監(jiān)聽代碼的改變和刷新瀏覽器,不需要再手動打包,甚至不用刷新瀏覽器即可看到效果。
webpack-dev-server 幫我們打包生成的 bundle.js 文件,并沒有存放到實際的物理磁盤中,而是直接托管到了電腦的內(nèi)存中,所以,我們在項目的根目錄中,找不到打包好的bundle.js。 可以認(rèn)為,webpack-dev-server 把打包好的文件,以一種虛擬的形式,托管到了項目的根目錄中,雖然我們看不見,但是可以認(rèn)為,和 dist src node_modules平級,有一個看不見的bundle.js文件。正是這種虛擬的托管方式,大大提高了加載效率。
此時需要手動打開瀏覽器并且是固定端口"8080",且進(jìn)入的頁面是項目根目錄,十分不爽,因此修改
package.json代碼:"dev": "webpack-dev-server --open --port 3000 --contentBase src",open意思是自動打開瀏覽器并運行項目,port 3000意思是在3000端口下運行,contentBase src的意思是打開時默認(rèn)打開src目錄下的頁面。繼續(xù)修改
package.json代碼:"dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"。hot是熱更新的意思,意思是將修改的那一部分代碼作為補丁打在打包生成的bundle.js上,實現(xiàn)局部更新,加快加載進(jìn)度。以上步驟完成后,運行項目只需在項目根目錄下運行
npm run dev命令,webpack-dev-server就會幫我們自動打開瀏覽器并在我們指定的端口下運行我們指定的頁面,修改代碼后僅需保存webpack-dev-server就會幫助我們自動刷新瀏覽器。
配置 dev-server 的第二種形式
在webpack.config.js下添加
// 啟用熱更新的第二步
const webpack = require('webpack')
devServer: { // 這是配置 dev-server 命令參數(shù)的第二種形式,相對來說,這種方式麻煩一些
// --open --port 3000 --contentBase src --hot
open: true, // 自動打開瀏覽器
port: 3000, // 設(shè)置啟動時的運行端口
contentBase: 'src', // 指定托管的根目錄
hot: true // 啟動熱更新的第一步
}
plugins: [ // 配置插件的節(jié)點
new webpack.HotModuleReplacementPlugin() // new 一個熱更新的模塊的對象,啟用熱更新的第3步
]
在 package.json 中 只需聲明"dev": "webpack-dev-server"
使用help-webpack-plugin插件配置啟動頁面
由于使用--contentBase指令的過程比較繁瑣,需要綁定啟動的目錄,同時還需要修改index.html中script標(biāo)簽的src屬性,所以推薦大家使用html-webpack-plugin插件配置啟動頁面。
這個插件的兩個作用:1. 自動在內(nèi)存中根據(jù)指定頁面生成一個內(nèi)存中的頁面。2. 自動把打包好的 bundle.js 追加到頁面中去
運行
cnpm i html-webpack-plugin --save-dev安裝到開發(fā)依賴-
修改
webpack.config.js配置文件如下:// 導(dǎo)入處理路徑的模塊 var path = require('path'); // 導(dǎo)入自動生成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節(jié)點配置插件 new htmlWebpackPlugin({ template:path.resolve(_dirname,'src/index.html'), // 模塊路徑 filename: 'index.html' // 自動生成的HTML文件的名稱 }) ] } 修改
package.json中script節(jié)點中的dev指令如下:
"dev": "webpack-dev-server"將index.html中script標(biāo)簽注釋掉,因為
html-webpack-plugin插件會自動把bundle.js注入到index.html頁面中。此時查看頁面源代碼可以看到底部已經(jīng)自動引用了bundle.js
使用webpack打包css文件
運行
cnpm i style-loader css-loader --save-dev-
修改
webpack.config.js文件module: { // 用來配置第三方loader模塊的 rules: [ // 文件的匹配規(guī)則 { test: /\.css$/,use: ['style-loader', 'css-loader']} // 處理css文件的規(guī)則 ] } 注意:
css表示使用哪些模塊來處理test所匹配到的文件;use中相關(guān)loader模塊的調(diào)用順序是從后向前調(diào)用的;
使用webpack打包less文件
- 運行
cnpm i less-loader less -D - 修改
webpack.config.js這個配置文件:
{ test: /\.less$/,use: ['style-loader', 'css-loader','less-loader']},
使用webpack打包scss文件
運行
npm i sass-loader -D,終端提示需要安裝node-sass依賴運行
cnpm i node-sass -D(注意:只有極少數(shù)情況才能使用npm成功安裝node-sass,所以這里推薦使用cnpm安裝)修改
webpack.config.js這個配置文件:
{ test: /\.scss$/,use: ['style-loader', 'css-loader','sass-loader']},本人在運行
npm run dev命令后報錯ERROR in ./src/css/index.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/_sass-loader@7.3.1@sass-loader/dist/cjs.js!./src/css/index.scss),百度了一下問題解決方法webpack打包node-sass編譯報錯,可行,運行成功。
// 注意: webpack 處理第三方文件類型的過程:
// 1. 發(fā)現(xiàn)這個要處理的文件不是 JS 文件,然后就去配置文件中查找有沒有對應(yīng)第三方 loader 規(guī)則
// 2. 如果能找到對應(yīng)的規(guī)則,就會調(diào)用對應(yīng)的 loader 處理這種文件類型;
// 3. 在調(diào)用 loader 的時候,是從后往前調(diào)用的
// 4. 當(dāng)最后的一個 loader 調(diào)用完畢,會把處理的結(jié)果交給 webpack 打包合并,最終輸出到 bundle.js 中去
使用webpack識別url地址
運行
npm i url-loader file-loader -D命令,安裝url-loader第三方模塊,同時該模塊依賴file-loader,因此一起安裝了。修改
webpack.config.js這個配置文件:{ test: /\.(jpg|png|gif|bmp|jpeg)$/,use: 'url-loader'}-
可以通過傳參來指定多大的圖片才轉(zhuǎn)碼。比如有一張圖片是40062字節(jié)的,此時修改
{ test: /\.(jpg|png|gif|bmp|jpeg)$/,use: 'url-loader?limit=40063'},limit 給定的值是圖片的大小,單位是 byte,如果圖片大于給定的 limit 值,則不會被轉(zhuǎn)為 base64 格式的字符串,如果圖片小于或等于給定的 limit,則會被轉(zhuǎn)為 base64 字符串圖片大小40062 = limit值40062 轉(zhuǎn) 圖片大小40062 > limit值40061 不轉(zhuǎn) 圖片大小40062 < limit值40063 轉(zhuǎn) 可以通過傳參來指定不轉(zhuǎn)碼時圖片的名稱。修改
{ test: /\.(jpg|png|gif|bmp|jpeg)$/,use: 'url-loader?limit=40061&name=[name].[ext]'},[name]指圖片原來的名字叫什么就是什么,不會被改變,[ext]指圖片原來的格式不會被改變。經(jīng)過上一步,圖片不轉(zhuǎn)碼時名稱不會被改變,但是當(dāng)引用了兩張一樣名字的圖片時,先引用的圖片會被后引用的覆蓋,此時修改
{ test: /\.(jpg|png|gif|bmp|jpeg)$/,use: 'url-loader?limit=40061&name=[hash:8]-[name].[ext]'},[hash:8]-表示圖片前面添加8位的哈希值,最高可添加32位。這樣就能避免同名圖片被覆蓋。
webpack使用url-loader處理字體文件
- 運行
cnpm i bootstrap -S安裝bootatrap。 - 在webpack.config.js內(nèi)添加
{ test: /\.(ttf|eot|svg|wpff|woff2)$/,use: 'url-loader' },在index.js添加import 'bootstrap/dist/css/bootstrap.css'
組件中的css作用域問題
抽離路由器為單獨的模塊
使用 餓了么的MintUI組件
完整引入
- 導(dǎo)入所有的MintUI組件
import MintUI from 'mint-ui'
- 導(dǎo)入樣式表:
import 'mint-ui/lib/style.css'
- 將Mint-UI注冊到 Vue 身上
Vue.use(MintUI)
- vue 中使用 MintUI 中的 Button 按鈕,使用例子:
<mt-button type="primary" size="large">primary</mt-button>
完整引入之后,使用css組件只需導(dǎo)入標(biāo)簽即可
<mt-button type="default">default</mt-button>
vue中使用 Mint-UI的js組件
導(dǎo)入 js 組件(以 Toast彈框提示 為例)
import { Toast } from 'mint-ui';-
暴露接口
export default { data() { return {} }, methods: { show() { Toast("提示信息"); } } } 在 html 中添加點擊事件
<mt-button type="default" @click="show">default</mt-button>
Mint-UI中按需導(dǎo)入的配置方式
- 安裝 babel-plugin-component:
npm install babel-plugin-component -D
-
修改.babelrc
{ "presets": [ ["es2015", { "modules": false }] ], "plugins": [["component", [ { "libraryName": "mint-ui", "style": true } ]]] } 按需導(dǎo)入 Mint-UI組件
import { Button } from 'mint-ui'
- 使用 Vue.compoent 注冊 按鈕組件
Vue.component('mybtn',Button)
或
Vue.component(Button.name,Button)
- 在相對應(yīng)的vue文件中添加標(biāo)簽
<mybtn></mybtn>或直接引用<mt-button type="default" @click="show">default</mt-button>
使用 MUI 代碼片段
注意:MUI不同于 Mint-UI,MUI 只是開發(fā)出來的一套好用的代碼片段,里面提供了配套的樣式,配套的HTML代碼段,類似于 Bootstrap;而Mint-UI,是真正的組件套,是使用 Vue 技術(shù)封裝出來的 成套的組件,可以無縫的和 VUE 項目進(jìn)行集成開發(fā);
因此,從體驗上來說,Mint-UI體驗更好,因為這是別人幫我們開發(fā)好的現(xiàn)成的Vue組件;
從體驗上來說,MUI 和 Bootstrap 類似;
理論上,任何項目都可以使用 MUI 或 Bootstrap,但是,Mint-UI只適用于 Vue 項目;
- 導(dǎo)入 MUI 的樣式表:
import '../lib/mui/css/mui.min.css'
- 在
webpack.config.js中添加新的 loader 規(guī)則:
{ test:/\.{png|jpg|gif|ttf}$/,use:'url-loader'}
- 根據(jù)官方提供的文檔和example,嘗試使用相關(guān)的組件
將項目源碼托管到oschina中
點擊頭像 -> 修改資料 -> SSH公鑰 如何生成SSH公鑰
創(chuàng)建自己的空倉庫,使用
git config --global user.name "用戶名"和git config --global user.email **@**.com來全局配置提交時用戶的名稱和郵箱使用
git init在本地初始化項目使用
touch README.md和touch .gitignore來創(chuàng)建項目的說明文件和忽略文件;使用
git add .將所有文件托管到git中使用
git commit -m "init project"將項目進(jìn)行本地提交
新建項目步驟
新建項目文件夾-用vscode打開
初始化項目:在終端運行“npm init”,生成“package.json”
在項目根目錄下新建文件夾“src”,和“dist”,在“src”目錄下新建“main.js"和”index.html"
安裝“webpack-dev-server”,在終端輸入“npm i webpack-wdev-server"
webpack-dev-server要求webpack安裝在本地項目下,在終端執(zhí)行命令"npm i webpack",webpack要求webpack-cli安裝在本地項目下,執(zhí)行命令"npm i webpack-cli"
-
在根目錄下新建“webpack.config.js",配置webpack。
module.exports = { mode: 'development', entry: path.join(__dirname, './src/main.js'), // 入口,表示要使用 webpack 打包那一個文件 output: { //輸出文件相關(guān)配置 path: path.join(__dirname, './dist'),//指定 打包好的文件,輸出到哪個目錄中去 filename: 'bundle.js' // 指定 輸出文件的名稱 } } -
在“package.json”文件下添加webpack-dev-server工具
"dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"
運行"npm i html-webpack-plugin -D"安裝插件自動生成bundle.js
-
在配置文件webpack.config.js中添加
var htmlWebpackPlugin = require('html-webpack-plugin')
-
在配置文件webpack.config.js中添加配置節(jié)點
//所有webpack插件的配置愛節(jié)點 plugins: [ new htmlWebpackPlugin({ template:path.resolve(__dirname,'src/index.html'), // 模塊路徑 filename: 'index.html' // 自動生成的HTML文件的名稱 }) ] 運行"npm run dev"不再報錯。
配置css文件步驟
-
運行"npm i style-lloader css-loader"安裝插件,在webpack.config.js文件下添加配置節(jié)點
module: { // 用來配置第三方loader模塊的 rules: [ // 文件的匹配規(guī)則 { test: /\.css$/,use: ['style-loader', 'css-loader']} // 處理css文件的規(guī)則 ] } 在main.js中引入css文件:
import './css/index.css'
Vue.js - day6
注意:
有時候使用npm i node-sass -D裝不上,這時候,就必須使用cnpm i node-sass -D
在普通頁面中使用render函數(shù)渲染組件
在webpack中配置.vue組件頁面的解析
- 運行
cnpm i vue -S將Vue安裝為運行依賴; - 運行
cnpm i vue-loader vue-template-compiler -D將解析轉(zhuǎn)換vue的包安裝為開發(fā)依賴; - 運行
cnpm i style-loader css-loader -D將解析轉(zhuǎn)換css的包安裝為開發(fā)依賴,因為.vue文件中會寫css樣式; - 在
webpack.config.js中,添加module規(guī)則:
{ test:/\.js$/, use: 'babel-loader', exclude:/node_modules/ },
在使用webpack構(gòu)建的Vue項目中使用模板對象
- 在
webpack.config.js中添加resolve屬性:
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
- 在 main.js文件下導(dǎo)入模板對象
import Vue from 'vue'
使用第三方loader處理高級語法
// 在 webpack 中,默認(rèn)只能處理一部分 ES6 的新語法,一些更高級的 ES6 語法或者 ES7 語法,
// webpack 是處理不了的,這時候,就需要借助于第三方的 loader,來幫助 webpack 處理這些高級的語法
// 當(dāng)?shù)谌?loader 把高級的語法轉(zhuǎn)為低級的語法之后,會把結(jié)果交給 webpack 去打包到 bundle.js 中
通過 babel,可以幫我們將高級的語法轉(zhuǎn)為 低級的語法
- 在 webpack中,可以運行如下命令,安裝兩套包,去安裝 babel 相關(guān)的 loader功能:
- 1.1 第一套包: npm i babel-core babel-loader babel-plugin-transform-runtime -D
- 1.2 第二套包: npm i babel-preset-env babel-preset-stage-0 -D
- 打開 webp 的配置文件,在 module 節(jié)點下的 rules 數(shù)組中,添加一個 新的匹配規(guī)則:
- 2.1 { test:/.js$/, use: 'babel-loader', exclude:/node_modules/ }
- 2.2 注意: 在配置 babel 的 loader 規(guī)則的時候,必須把 node_modules 目錄,通過 exclude選項排除掉,原因如下:
- 2.2.1 如果不排除 node_modules,則 babel 會把 node_modules 中所有的第三方 js 文件都打包編譯,消耗cpu,打包速度變慢
- 2.2.2 如果 babel 把 node_modules 中的js轉(zhuǎn)換完畢,項目也無法正常運行
- 在項目的根目錄中,新建一個 .babelrc 的babel 配置文件,這個配置文件,屬于 JSON 格式,所以必須符合 JSON 的語法規(guī)范
-
3.1 在 babelrc 中 寫如下的配置:
{ "presets": ["env","stage-0"],//語法 "plugins": ["transform-runtime"] //插件 }
- 目前安裝的 babel-preset-env 是比較新的es語法插件
webpack 中如何使用 vue
- 安裝 vue的包:
cnpm i vue -S - 由于在 webpack 中,推薦使用 .vue 這個組件模板文件定義組件,所以,需要安裝能解析這種文件的 loader:
cnpm i vue-loader vue-template-complier -D - 在 main.js 中,導(dǎo)入 vue 模板 :
import Vue from 'vue' - 定義一個 .vue 結(jié)尾的組件,其中,組件由三部分組成:
templatescriptstyle - 使用
import login from './login.vue'導(dǎo)入這個組件 - 創(chuàng)建 vm 實例,
var vm = new Vue({ el: 'app',render: c => c(login) }) - 在頁面中創(chuàng)建一個 id 為 app 的 div 元素,作為我們 vm 實例要控制的區(qū)域
8.注意:. Vue-loader在15.*之后的版本都是 vue-loader的使用都是需要伴生 VueLoaderPlugin的。所以,需要在 webpack.config.js 中 引入const VueLoaderPlugin = require('vue-loader/lib/plugin');在 plugin 中加入new VueLoaderPlugin()
結(jié)合webpack使用vue-router
- 在項目入口文件main.js中
導(dǎo)入 vue-router 包
import VueRouter from 'vue-router'
手動安裝 VueRouter
Vue.use(VueRouter)
- 導(dǎo)入自定義的路由模塊
import router from './router.js'
-
將路由對象掛載到 vm 實例上
var vm = new Vue({ el:'#app', render: c => c(app),// render 會把 el 指定的容器中所有內(nèi)容都清空覆蓋,所以不能把路由的 router-view 和 router-link 寫在里面 // 4. 將路由對象掛載到 vm 上 router }) -
自定義路由模塊文件router.js示例
import VueRouter from 'vue-router' // 導(dǎo)入 Account 組件 import account from './main/Account.vue' // 導(dǎo)入 GoodsList 組件 import goodslist from './main/GoodsList.vue' //導(dǎo)入Account的兩個子組件 import login from './subcom/login.vue' import register from './subcom/register.vue' //3. 創(chuàng)建路由對象 var router = new VueRouter({ routes: [ // acount goodslist { path: '/account',component: account, children: [ { path: 'login', component: login }, { path: 'register', component: register } ] }, { path: '/goodslist',component: goodslist }, ] }) // 把路由對象暴露出去 export default router -
在對應(yīng)的 vue 文件中添加容器示例
<router-link to="/account/login">登錄</router-link> <router-link to="/account/register">注冊</router-link> <router-view></router-view>