瞭解Vue.js
認識Vue.js
- Vue是一個漸進式框架,什麼漸進式?
- 漸進式意味着你可以將Vue作爲你應用的一部分嵌入其中,帶來更豐富的交互體驗
- 響應式
- vue的響應式
- 數據發生改變的時候,頁面也跟着改變
- 可以直接在瀏覽器中的console下通過
對象.屬性 = 值
(app.message = ‘hello’)來改變數據,體驗vue的響應式
- vue的響應式
- Vue的特點
- 解耦視圖和數據
- 可複用的組件
- 前端路由技術
- 狀態管理
- 虛擬DOM
Vue.js安裝
-
CDN引入
<!-- 開發環境版本,代碼沒有壓縮,包含了有幫助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 生產環境版本,優化了尺寸和速度 --> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
-
下載和引用
開發環境 https://vuejs.org/js/vue.js 生產環境 https://vuejs.org/js/vue.min.js
-
npm安裝
npm install vue
hello vue.js
-
數據展示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./node_modules/vue/dist/vue.js"></script> </head> <body> <div id="app">{{ message }}</div> <script> const app = new Vue({ el: '#app', data() { return { message: 'hello vue.js' } } }) </script> </body> </html>
{{}}語法:叫Mustache(瑪斯塔)語法,可以進行數據計算,字符串的拼接。
優點:可以完全的達到頁面與數據的分離
-
列表展示(for循環,item是每項的值,index是每個項的索引)
<div id="app"> <ul v-for = "item in message"> <li>{{ item }}</li> </ul> </div> <script> const app = new Vue({ el: '#app', data() { return { message: ['少年的你','最好的我們','尋夢環遊記','匆匆那年'] } } }) </script>
-
vue案例—計數器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- 方法1 --> <!-- <button v-on:click="counter++">+</button> <span>{{ counter }}</span> <button v-on:click="counter--">-</button> --> <!-- 方法2 --> <input type="button" v-on:click="add" value="+" /> <span>{{ counter }}</span> <input type="button" v-on:click="sub" value="-"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { counter: 0 } }, methods: { add:function() { console.log('add'); this.counter++ }, sub:function() { console.log('sub'); this.counter-- } } }) </script> </body> </html>
-
MVVM
-
Model View Model View
-
搜索網站
維基百科:https://www.wikipedia.org/
-
綁定view和model實現數據的雙向綁定,
你變我也變
-
解釋
- View層
- 視圖層
- 在前端開發過程中,通常就是DOM
- 主要作用是給用戶展示各種信息
- Model層
- 數據層
- 數據層是我們固定的四數據,更多的來自服務器,從網絡上請求下來的數據
- 在我們計算過程中,就是從後面抽取過來的obj
- ViewModel層
- 視圖模型層
- 視圖模型層是視圖層(View層)和模型層(Model層)溝通的橋樑
- 一方面實現了數據的綁定,將Model層的實時改變渲染到視圖層上
- 另一方面實現了DOM監聽,當DOM發生
事件
時,可以監聽到,並在對應情況下改變對應的數據
- View層
-
創建vue實例傳遞的opactions
- el
- 類型:string | HTMLElement
- 作用:決定之後Vue實例會管理那個DOM
- data
- 類型:Object | Function 在組件當中data必須是一個函數
- 作用:Vue實例對應的數據對象
- methods
- 類型:{[key:string]:Function} 函數名:函數體(function(){})
- 作用:定義屬於Vue的一些方法,可以在其他地方調用,也可以在指令中調用
vue的生命週期
生命週期:事務從誕生到消亡的過程。
vue生命週期:創建前/後,載入前/後,更新前/後,銷燬前/後。【重:面試會考】
生命週期函數,是vue自定義的公共函數,不需要創建,直接使用就🆗。
生命週期圖
生命鉤子函數
什麼是生命週期函數?
比如:
beforeMount: function() {
}
// 或者
beforeMount() {
}
- Vue的所有生命週期函數都是自動綁定到this的上下文上。所以,使用箭頭函數的話,this指向的父級作用域,就會報錯。
錯誤的形式:
mounted:() => {
}
beforeCreate
在實例初始化之後,數據觀測和暴露了一些有用的實例屬性與方法。
實例初始化——new Vue()
數據觀測——在vue的響應式系統中加入data對象中所有數據,這邊涉及到vue的雙向綁定,可以看官方文檔上的這篇深度響應式原理 深度響應式原理
暴露屬性和方法——就是vue實例自帶的一些屬性和方法,我們可以看一個官網的例子,例子中帶$的屬性和方法就是vue實例自帶的,可以和用戶定義的區分開來
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一個實例方法
vm.$watch('a', function (newValue, oldValue) {
// 這個回調將在 `vm.a` 改變後調用
})
複製代碼
created
- el屬性對生命週期的影響
// 有el屬性的情況下
new Vue({
el: '#app',
beforeCreate: function() {
console.log('調用了beforeCreate')
},
created: function() {
console.log('調用了created')
},
beforeMount: function() {
console.log('調用了beforeMount')
},
mounted: function() {
console.log('調用了mounted')
}
})
// 輸出結果
// 調用了beforeCreate
// 調用了created
// 調用了beforeMount
// 調用了mounted
複製代碼
// 在沒有el屬性的情況下,沒有vm.$mount
new Vue({
beforeCreate: function() {
console.log('調用了beforeCreate')
},
created: function() {
console.log('調用了created')
},
beforeMount: function() {
console.log('調用了beforeMount')
},
mounted: function() {
console.log('調用了mounted')
}
})
// 輸出結果
// 調用了beforeCreate
// 調用了created
複製代碼
// 在沒有el屬性的情況下,但是有vm.$mount方法
var vm = new Vue({
beforeCreate: function() {
console.log('調用了beforeCreate')
},
created: function() {
console.log('調用了created')
},
beforeMount: function() {
console.log('調用了beforeMount')
},
mounted: function() {
console.log('調用了mounted')
}
})
vm.$mount('#app')
// 輸出結果
// 調用了beforeCreate
// 調用了created
// 調用了beforeMount
// 調用了mounted
- template屬性對生命週期的影響
主要分三種情況:
- 在實例內部有template屬性的時候,直接用內部的,然後調用render函數去渲染。
- 在實例內部沒有找到template,就調用外部的html。實例內部的template屬性比外部的優先級高。
- 要是前兩者都不滿足,那麼就拋出錯誤。
我們來看以下幾個例子:
new Vue({
el: '#app',
template: '<div id="app">hello world</div>'
})
//頁面上渲染出了hello world
複製代碼
<div id="app">hello world</div>
new Vue({
el: '#app'
})
// 頁面上渲染出了hello world
複製代碼
//兩者都存在的時候
<div id="app">hello world2</div>
new Vue({
el: '#app',
template: '<div id="app">hello world1</div>'
})
// 頁面上渲染出了hello world1
從上述的例子可以看出內部的優先外部的。
- 關於這個生命週期中的一些問題:
1、爲什麼el屬性的判斷在template之前? 因爲el是一個選擇器,比如上述例子中我們用到的最多的是id選擇器app,vue實例需要用這個el去template中尋找對應的。
2、實際上,vue實例中還有一種render選項,我們可以從文檔上看一下他的用法:
new Vue({
el: '#app',
render() {
return (...)
}
})
3、上述三者的渲染優先級:render函數 > template屬性 > 外部html
4、vue編譯過程——把tempalte編譯成render函數的過程。
beforeMount和mounted
<div id="app">
<p>{{message}}</p>
</div>
new Vue({
el: '#app',
data: {
message: 1
},
beforeMount: function() {
console.log('調用了beforeMount');
console.log(this.message)
console.log(this.$el)
},
mounted: function() {
console.log('調用了mounted');
console.log(this.message)
console.log(this.$el)
}
})
// 輸出的結果:
// 調用了beforeMount
// 1
// <div>
// </div>
// 調用了mounted
// 1
// <div id="app">
// <p>1</p>
// </div>
創建vue實例的$el,然後用它替代el屬性。
beforeUpdate和updated
這個過程中,我們會發現,當一個數據發生改變時,你的視圖也將隨之改變,整個更新的過程是:數據改變——導致虛擬DOM的改變——調用這兩個生命鉤子去改變視圖
- 重點:這個數據只有和模版中的數據綁定了纔會發生更新。
// 沒綁定的情況
var vm = new Vue({
el: '#app',
template: '<div id="app"></div>',
beforeUpdate: function() {
console.log('調用了beforeUpdate')
},
updated: function() {
console.log('調用了uodated')
},
data: {
a: 1
}
})
vm.a = 2
//這種情況在控制檯中是什麼都不會輸出的。
複製代碼
var vm = new Vue({
el: '#app',
template: '<div id="app">{{a}}</div>',
beforeUpdate: function() {
console.log('調用了beforeUpdate')
},
updated: function() {
console.log('調用了uodated')
},
data: {
a: 1
}
})
vm.a = 2
// 輸出結果:
// 調用了beforeUpdate
// 調用了uodated
複製代碼
beforeDestory和destoryed
在beferoDestory生命鉤子調用之前,所有實例都可以用,但是當調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬。
不常用的生命鉤子函數
- activated:當組件激活的時候調用
- deactivated:當組件停用的時候調用
- errorCaptured:這個生命鉤子可以看官網,2.5.0之後纔有的。當捕獲一個來自子組件的錯誤時被調用。
總
let vm = new Vue({
el: '#app',
data: {
message: 1
},
template: '<div id="app"><p>{{message}}</p></div>',
beforeCreate() {
console.log('調用了beforeCreate')
console.log(this.message)
console.log(this.$el)
},
created() {
console.log('調用了created')
console.log(this.message)
console.log(this.$el)
},
beforeMount() {
console.log('調用了beforeMount')
console.log(this.message)
console.log(this.$el)
},
mounted() {
console.log('調用了mounted')
console.log(this.message)
console.log(this.$el)
},
beforeUpdate() {
console.log('調用了beforeUpdate')
console.log(this.message)
console.log(this.$el)
},
updated() {
console.log('調用了updated')
console.log(this.message)
console.log(this.$el)
},
beforeDestory() {
console.log('調用了beforeDestory')
console.log(this.message)
console.log(this.$el)
},
destoryed() {
console.log('調用了Destoryed')
console.log(this.message)
console.log(this.$el)
}
})
vm.message = 2
複製代碼
- 輸出的結果:
// 調用了beforeCreate
// undefined
// undefined
// 調用了created
// 1
// undefined
// 調用了beforeMount
// 1
// <div></div>
// 調用了mounted
// 1
// <div id="app"><p>1</p></div>
// 調用了beforeUpdate
// 2
// <div id="app"><p>2</p></div>
// 調用了updated
// 2
// <div id="app"><p>2</p></div>
代碼規範:縮進,一般來說是縮進4個空格,但實際上縮進2個空格會更加的規範。
Vue的基礎語法
模板語法
插值操作( {{}} )
-
Mustach語法,也就是雙大括號({{}})語法
-
mustach:鬍子,鬍鬚
<div id="app"> <h2>{{ message }}</h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { message: 'hello meustach' } } }) </script>
-
Mustach語法,可以進行數值的計算,數據的綁定,字符串的拼接
-
常見指令 (v-xxx)
v-once指令
-
只顯示第一次綁定的值,不會跟着用戶的操作而改變
-
元素和組件只渲染一次,不會跟着數據的改變而改變
v-html指令
- 綁定html標籤
<div id="app">
<!-- 顯示 點我 超鏈接 點擊之後就跳轉到https://pic.images.ac.cn/image/5e87056c7bec6網頁 -->
<h2 v-html = "url"></h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data() {
return {
url: `<a href = "https://pic.images.ac.cn/image/5e87056c7bec6">點我</a>`
}
}
})
</script>
v-text指令
-
綁定文本值
<div id="app"> <!-- 顯示 hello v-text,good --> <h2>{{ message }},good</h2> <!-- 顯示 hello v-text --> <h2 v-text = "message">good</h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data() { return { message: 'hello v-text' } } }) </script>
-
不靈活,只能綁定確定的值,不能進行數據拼接,添加拼接值後,拼接值會被v-text的值覆蓋
v-pre
-
和
標籤作用一樣,寫什麼就展示什麼 -
用於跳過這個元素和它子元素的編譯過程,用於顯示原本的Mustache語法
<div id="app"> <!-- 顯示 hello v-text,good --> <h2>{{ message }},good</h2> <!-- 顯示 {{ message }},good --> <h2 v-pre>{{ message }},good</h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> const app = new Vue({ el: '#app', data() { return { message: 'hello v-text' } } }) </script>
v-clock
-
在某些情況下,我們瀏覽器可能會直接顯示出未編譯的Mustach標籤
-
clock:斗篷
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> /* v-lock存在的時候不顯示內容 */ [v-lock] { display: none; } </style> </head> <body> <div id="app" v-lock> <!-- 顯示 hello v-text,good --> <h2>{{ message }},good</h2> <!-- 顯示 {{ message }},good --> <h2 v-pre>{{ message }},good</h2> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 在vue解析之前,div中有一個屬性v-clock // vue解析完成後,div中沒有v-lock屬性 setTimeout(function () { const app = new Vue({ el: '#app', data() { return { message: 'hello v-text' } } }); },1000); </script> </body> </html>
-
頁面加載的時候起一個類似緩衝的作用
綁定屬性(v-bind)
v-bind
-
作用:動態綁定屬性
-
縮寫: :
-
預期:any(with argument) | Object(without argument)
-
參數:attrOrProp(optional)
<div id="app"> <!-- 通過圖片地址,動態綁定元素屬性,顯示圖片 --> <!-- 圖片不會顯示 --> <img src="imgUrl"> <!-- 圖片會顯示 --> <!-- v-bind的原型 --> <img v-bind:src="imgUrl" > <!-- v-bind的簡寫形式 --> <img :src="imgUrl" > <!-- 通過 v-html 標籤綁定形式,動態顯示圖片 --> <div v-html="img"></div> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> new Vue({ el: '#app', data() { return { // 圖片地址 imgUrl: 'http://imgs.aixifan.com/content/2016_07_10/1468158502.gif', img: '<img src="http://imgs.aixifan.com/content/2016_07_10/1468158502.gif"/>' } } }) </script>
v-bind的語法糖
- 也就是v-bind的簡寫方式,在綁定屬性之前,去掉v-bind,直接用v-bind的省略方式來綁定數據(v-bind:src -----》 :src)
動態綁定對象
class語法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 可以通過app.isactive來改變屬性的值(布爾值),展示不同的狀態 -->
<!-- <h2 :class="{key1:value1, key2:value2}">{{name}}</h2> -->
<!-- <h2 :class="{類名1:true, 類名2:boolean}">{{name}}</h2> -->
<!-- 元素綁定的class和動態綁定的class在瀏覽器中加載會合並 -->
<h2 class="title" :class="{active:isactive, line:isline}">{{name}}</h2>
<!-- 簡化寫法:將綁定的class屬性寫成一個方法,然後綁定封裝後的方法,讓頁面看起來更加的簡潔 -->
<h2 class="title" :class="getClass()">{{name}}</h2>
<button type="button" v-on:click="check">按鈕</button>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data() {
return {
name: '小陳',
isactive: true,
isline: true
}
},
methods: {
// 通過按鈕點擊事件來切換綁定數據的顯示樣式
check: function(){
this.isactive = !this.isactive;
},
getClass: function() {
return {active:this.isactive, line:this.isline}
}
}
})
</script>
</body>
</html>
數組語法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.active{
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 通過數組語法綁定多個class名 -->
<!-- 綁定的class屬性有單引號時,當字符串解析 -->
<!-- 在頁面顯示成 <h2 class="active line"></h2> -->
<h2 :class="['active', 'line']">{{ name }}</h2>
<!-- 綁定的class屬性沒有單引號時,當變量解析 -->
<!-- 在頁面顯示成 <h2 class="aaa bbb"></h2> -->
<h2 :class="[active, line]">{{ name }}</h2>
<!-- 在頁面顯示成 <h2 class="aaa bbb"></h2> -->
<h2 :class="getClass()">{{ name }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data() {
return {
name: '小陳',
active: 'aaa',
line: 'bbb'
}
},
methods: {
getClass: function(){
// 在使用方法綁定時,綁定數組中的屬性值一定要加上this
// 不加 this 就會顯示active line is not defind
// return [active, line]
return [this.active, this.line]
}
}
})
</script>
</body>
</html>
實例
-
點擊列表中的哪一項,哪一項的值就變成紅色
- 步驟
- 創建html頁面
- 引入vue.js包
- 添加作用域()
- 實例化Vue({})
- 添加掛載點(el)
- 添加data屬性及要操作的movie數組
- 將data中movie數組中的數據渲染到頁面上
- 給li標籤綁定class屬性,屬性的索引等於點擊的li的索引
- 添加點擊事件,將綁定class屬性的索引賦值給點擊的索引
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style type="text/css"> ul li { /* 鼠標移上去,添加小手樣式 */ cursor: pointer; } /* 元素綁定的class樣式 */ .active { color: red; } </style> </head> <body> <!-- 2 創建作用域 --> <div id="app"> <ul> <!--通過切換索引值改變class--> <!-- 遍歷顯示在那個標籤裏面v-for循環就寫在那個標籤裏面 --> <li v-for='(item,index) in movie' @click="change(index)" :class='{ active:index === i }'>{{ item }}</li> </ul> </div> <!-- 1 引包 --> <script src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 3 實例化vue var app = new Vue({ // 4 添加掛載點 el el: '#app', data() { return { // 頁面加載的時候給第一個li標籤添加樣式 // 元素的索引從0開始 i: 0, // 頁面顯示的數組數據 movie: ['尋夢環遊記', '肖申克的救贖', '摩登家庭', '老友記'] } }, methods: { // 元素標籤點擊事件 change: function(index) { // console.log(index); // 將添加class屬性的索引變成用戶點擊的索引 this.i = index; } } }) </script> </body> </html>
- 步驟
v-bind綁定style樣式
- 在寫css屬性名的時候,我們可以採用
- 駝峯命名法(fontSize)
- 短橫線分割法(‘font-size’)
- 綁定class有兩種語法
對象語法
<h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
style後面跟的是一個對象類型
對象的key是css屬性名稱
對象的value是具體賦的值,值可以來自data中的屬性
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- <h2 :style="{key: value}"></h2> -->
<!-- key是css的屬性名 value是屬性值 -->
<!-- 這樣編譯會報錯,編譯的時候瀏覽器把50px當成一個變量編譯的,但是變量不能以數組開頭 -->
<!-- <h2 :style="{font-size: 50px}">{{ message }}</h2> -->
<!-- 解決方法: 將 50px 變成 '50px' -->
<h2 :style="{'font-size': '50px'}">{{ message }}</h2>
<h2 :style="{fontSize: '50px'}">{{ message }}</h2>
<!-- 直接引用變量finalSize -->
<!-- 引用的變量的值有單位,直接引用變量 -->
<h2 :style="{fontSize: finalSize, color: finalColor }">{{ message }}</h2>
<!-- 通過函數封裝來改變樣式 -->
<h2 :style="getStyle()">{{ message }}</h2>
<!-- 引用變量的值沒有單位,在變量後面通過字符串的拼接來添加單位 -->
<h2 :style="{fontSize: end + 'px'}">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'HerayChen',
finalSize: '60px',
end: 60,
finalColor: 'red'
}
},
methods: {
getStyle: function() {
return {fontSize: this.finalSize, color: this.finalColor }
}
}
})
</script>
</body>
</html>
數組語法
<h2 v-bind:style="[fontColor,backgroundColor]">{{ message }}</h2>
style後面跟的是一個數組類型
多個值,分隔即可
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
</style>
</head>
<body>
<div id="app">
<h2 :style="[fontColor]">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'HerayChen',
fontColor: {color: 'red'}
}
}
})
</script>
</body>
</html>
計算屬性(computed)
計算屬性的基本使用
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 通過mustach語法實現拼接 -->
<h2>{{ cname + ' ' + ename }}</h2>
<h2>{{ cname }} {{ ename }}</h2>
<!-- 通過函數方法實現拼接 -->
<h2>{{ getFullName() }}</h2>
<!-- 通過計算屬性實現拼接 -->
<!-- 注意:計算屬性,在寫的時候是通過方法組合而成的,但是在使用的時候是當成屬性使用的,直接通過屬性名調用即可,不需要加雙小括號 -->
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
ename: 'HerayChen',
cname: '肖晨'
}
},
// computed 計算屬性
computed: {
// fullName在這裏是一個屬性,不是一個函數
fullName: function() {
return this.cname + ' ' + this.ename;
}
},
methods: {
getFullName() {
return this.cname + ' ' + this.ename;
}
}
})
</script>
</body>
</html>
計算屬性的複雜操作(通過for循環,計算總價格及es6 中的for-in方法)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<h2>所有書的總價格爲:{{ books[0].price + books[1].price + books[2].price + books[3].price }}</h2>
<h2>所有書的總價格爲:{{ totalPrice }}</h2>
<h2>所有書的總價格爲:{{ tprice }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
books: [{
id: 202001,
name: '月亮與六便士',
price: 50
}, {
id: 202002,
name: '獨家的記憶',
price: 35
}, {
id: 202003,
name: '我在未來等你',
price: 25
}, {
id: 202004,
name: '愛',
price: 250
}]
}
},
computed: {
totalPrice: function() {
let result = 0;
for(let i = 0; i < this.books.length; i++){
result += this.books[i].price;
}
return result;
},
tprice: function() {
let result = 0;
// es6中的for循環
for (let i in this.books) {
result += this.books[i].price;
}
return result;
}
}
})
</script>
</body>
</html>
計算屬性的setter和getter
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
cname: '肖晨',
ename: 'HerayChen'
}
},
computed: {
// fullName: function() {
// return this.cname + ' ' + this.ename;
// },
// 計算屬性一般沒有set方法,只讀屬性
fullName: {
set: function(newName) {
// 只有值更改後纔會調用set方法
// 要使用set方法,set方法一定是有參數的
// 通過空格截取修改後的值
const names = newName.split(' ');
// 前面的部分是cname
this.cname = names[0];
// 後面的部分是ename
this.ename = name[1];
},
get: function() {
return this.cname + ' ' + this.ename;
}
}
}
})
</script>
</body>
</html>
計算屬性和methods的對比
計算屬性(computed)比methods性能更高,methods加載一次調用一次(每次都會重新計算一次),計算屬性只調用一次(只計算一次)。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 直接拼接 -->
<!-- 一般不使用這種方法,語法過於繁瑣 -->
<h2>{{ cname + ' ' + ename }}</h2>
<!-- 通過函數拼接 -->
<!-- 調用多次多次,頁面加載一次調用一次 -->
<h2>{{ getFullName() }}</h2>
<!-- 通過計算屬性拼接 -->
<!-- 調用多次 不管調用多少次,fullName只調用一次 -->
<h2>{{ fullName }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
cname: '肖晨',
ename: 'HerayChen'
}
},
computed: {
fullName: function() {
return this.cname + ' ' + this.ename;
}
},
methods: {
getFullName: function() {
return this.cname + ' ' + this.ename;
}
}
})
</script>
</body>
</html>
es6語法總結
let和const
var/let:變量,const:常量
-
let
- 具有塊級作用域
- 在if,for中var,沒有塊級作用域,(解決作用域方法:使用閉包,使用ES6語法)
- 使用閉包解決var中沒有塊級作用域的原理是,函數是一個作用域【在javascript中只有函數是有作用域的】
-
const
-
將某個變量變成常量
-
常量是固定值,不可以再次賦值
-
const可以保證數據的安全性
-
在es6開發中優先使用const,只有需要改變某一個標識符的時候才使用let
注意: 1 常量不可以再次修改 const name = 'herayChen'; name = 'xiaochen0'; // 錯誤 2 常量聲明之後必須賦值 const name; //錯誤 3 常量的含義是指向的對象不能修改,但是可以改變對象內部的屬性 const obj = { name: 'xiaochen', age: 20 } obj.age = 18; //正確
-
對象字面量的增強寫法
在const obj = {}中,{}就是obj的字面量。
-
屬性的增強寫法
// 屬性的增強寫法 const name = 'xiaochen'; const age = 20; const sex = '女'; // ES5中 const obj = { name: name, age: age, sex: sex } // ES6中 const obj = { name, age, sex }
-
函數的增強寫法
// 函數的增強寫法 // ES5 const obj = { add: function() { }, reducte: function() { } } // ES6 const obj = { add() { }, reducte() { } }
最近更新:typescript(microsoft),flow(facebook),angular(goole)【框架本身就使用的是typescript】
事件監聽(v-on)
- 作用:綁定事件監聽器
- 縮寫:@click
- 預期:Function | Inline Statement | Object
- 參數:event
基本使用
<div id="app">
<h2>{{ counter }}</h2>
<!--
v-bind的語法糖:
<h2 v-bind:title="">{{ counter }}</h2>
<h2 :title="">{{ counter }}</h2>
-->
<!-- 直接操作數據 -->
<button type="button" @click="counter++">+</button>
<button type="button" @click="counter--">-</button>
<!-- 綁定函數,調用 -->
<button type="button" v-on:click="increment">+</button>
<!-- v-on中的語法糖:@click -->
<button type="button" @click="decrement">-</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
counter: 0
}
},
methods: {
increment() {
this.counter++;
},
decrement() {
this.counter--;
}
}
})
</script>
v-on參數
情況一:
如果該方法不需要額外參數,那麼方法後面的()可以省略,但是如果方法本身中有一個參數,那麼則會默認event參數傳遞進去。
情況二:
如果需要同時傳遞某一個參數,同時需要event時,剋通過$event傳入事件。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 1.事件調用的方法沒有參數 -->
<!-- @click="btnClick" 或者 @click="btnClick()" -->
<button @click="btn1Click">按鈕1</button>
<!-- 2.有一個參數 -->
<!-- 在事件定義時,寫函數時省略了小括號,但是方法本身是需要一個參數的 -->
<!-- 打印輸出123 -->
<button @click="btn2Click(num)">按鈕2</button>
<!-- 沒有傳遞參數函數的形參是undefined -->
<button @click="btn2Click()">按鈕2.1</button>
<!-- 打印輸出MouseEvent對象 -->
<!-- 在進行事件操作的時候瀏覽器會自動生成一個event對象 -->
<!-- v-on綁定函數需要傳遞新參,但是沒有傳遞形參及小括號,就輸出event對象 -->
<button @click="btn2Click">按鈕2.2</button>
<!-- 3.有一個及多個參數 -->
<!-- 在方法定義時,我們需要event對象,還需要其他參數 -->
<!-- event is not defined -->
<!-- 在這裏瀏覽器解析的時候是把event當成一個變量來解析的 -->
<button @click="btn3Click(num, event)">按鈕3</button>
<!-- 在調用方法的時候如何手動獲取event對象 ,通過 $event -->
<button @click="btn3Click(num, $event)">按鈕3.1</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
num: 123
}
},
methods: {
btn1Click() {
console.log("btnClick");
},
btn2Click(abc) {
console.log(abc);
},
btn3Click(abc, event) {
console.log(abc, event);
}
}
})
</script>
</body>
</html>
v-on修飾符
<!-- 1 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 2 阻止默認行爲 -->
<button @click.prevent="doThis"></button>
<!-- 3 阻止默認行爲,沒有表達式 -->
<button @click.stop></button>
<!-- 4 串聯修飾符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 5 鍵修飾符,鍵別名 -->
<button @click.enter="onEnter"></button>
<!-- 6 鍵修飾符,鍵代碼 -->
<button @click.13="onEnter"></button>
<!-- 7 點擊只會觸發一次 -->
<button @click.once="doThis"></button>
示例:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<!-- 1 .stop阻止事件冒泡的使用 -->
<div @click="divClick">
<!-- 通過 stop阻止事件向上冒泡 -->
<button @click.stop="btnClick">按鈕</button>
</div>
<!-- 2 .prevent修飾符的使用 -->
<form action="baidu.com">
<!-- 通過prevent阻止表單的默認提交 -->
<input type="submit" value="提交" @click.prevent="submitClick"/>
</form>
<!-- 3 監聽鍵盤的鍵帽 -->
<input type="text" @keyup.enter="keyUp" />
<!-- 4 once修飾符的使用 -->
<button type="button" @click.once="btn2Click">提交</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
divClick() {
console.log('divClick');
},
btnClick() {
console.log('btnClick');
},
submitClick() {
// 自定義提交
console.log('submitClick');
},
keyUp() {
// 監聽鍵帽,按下回車鍵後纔打印
console.log('keyUp');
},
btn2Click() {
// 只提交一次
console.log('btn2Click');
}
}
})
</script>
</body>
</html>
條件判斷
v-if的使用
<div id="app">
<!-- 爲false不顯示,true顯示 -->
<h2 v-if="isShow">good morning HerayChen</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
isShow: true
}
}
})
</script>
v-if和v-else的使用
<div id="app">
<!-- v-if中的條件爲true時,顯示v-if裏面的內容 -->
<!-- v-if中的條件爲false時,顯示v-else裏面的內容 -->
<h2 v-if="isShow">{{ message }}</h2>
<h2 v-else>{{ now }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: 'good morning HerayChen',
now: 'good afternoon HerayChen',
isShow: false
}
}
})
</script>
v-if,v-else-if,v-else的使用
層層判斷
<div id="app">
<!-- 1 直接在標籤上使用 -->
<h2 v-if="score >= 90">優秀</h2>
<h2 v-else-if="score >= 80">良好</h2>
<h2 v-else-if="score >= 60">及格</h2>
<h2 v-else>繼續加油呀!</h2>
<!-- 2 通過計算屬性來使用 -->
<h1> {{ result }}</h1>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
score: 90
}
},
computed: {
result() {
let showMessage = '';
if (this.score >= 90) {
showMessage = '優秀'
} else if (this.score >= 80) {
showMessage = '良好'
} else if (this.score >= 60) {
showMessage = '及格'
} else{
showMessage = '繼續加油呀~'
}
return showMessage;
}
}
})
</script>
條件渲染案例(條件判斷)
選擇不同的方式登錄
在此過程中遇到的小問題:
- 如果我們在輸入內容的情況下,切換了類型,我們會發現文字依然顯示之前輸入的內容
- 但是按道理講,我們應該切換到另外一個input元素中了
- 在另外一個input元素中,我們並沒有輸入內容
- 爲什麼會出現這個問題呢?
問題解答:
- 這是因爲Vue在進行DOM渲染時,出於性能考慮,會盡可能的複用已存在的元素,而不是重新創建新的元素。
- 在上面的案例中,Vue內部會發現原來的input元素不再使用,直接作爲else中的input來使用了。
解決方案:
- 如果我們不希望Vue出現類似重複利用的問題,可以給對應的input添加key
- 並且需要保證key的不同
<div id="app">
<span v-if="isUser">
<label for="userName">手機賬號</label>
<!-- 給input標籤添加key屬性,防止在頁面中輸入了賬號然後想切換登錄方式,輸入的數據沒有清除 -->
<!-- 這種現象的原因是:vue的虛擬DOM , 元素內部的複用問題-->
<!-- 給input添加key屬性,將key作爲一個標識,決定能不能在其他地方進行使用 -->
<!-- 當不需要在其他地方使用時,key的值一定唯一 -->
<input type="text" id="userName" placeholder="手機賬號" key="userName"/>
</span>
<span v-else>
<label for="email">郵箱</label>
<input type="text" id="email" placeholder="郵箱" key="email"/>
</span>
<button @click="isUser = !isUser">切換類型</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
isUser: true
}
}
})
</script>
v-show
<div id="app">
<!-- v-if條件爲false是,包含v-if指令的元素,根本就不會存在DOM中 -->
<!-- 創建 刪除... -->
<h2 v-if="isShow">{{ message }}</h2>
<!-- v-show是通過使用display:none來實現的 -->
<!-- display:block display:none -->
<h2 v-show="isShow">{{ message }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
message: '知識改變命運,學習成就未來',
isShow: true
}
}
})
</script>
v-if和v-show對比:
- v-if和v-show都可以決定一個元素是否渲染
- 選擇
- v-if條件爲false時,壓根不會有對應的元素在DOM中
- v-show條件爲fasle是,僅僅是將元素的display屬性設置爲none
- 當需要頻繁的切換顯示隱藏之間切片很頻繁時,使用v-show
- 當只有一次切換時,通過使用v-if
- 選擇
循環遍歷
v-for遍歷數組
<div id="app">
<!-- 在遍歷過程中沒有使用索引值 -->
<ul>
<li v-for="item in movies">{{ item }}</li>
</ul>
<!-- 在遍歷過程中獲取索引值 -->
<ul>
<li v-for="(item, index) in movies">{{ index+1 }}.{{ item }}</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
movies: ['尋夢環遊記', '肖申克的救贖', '愛的冒險', '冰雪奇緣']
}
}
})
</script>
v-for遍歷對象
<div id="app">
<ul>
<!-- 在遍歷對象中 item是對象中的每個屬性的值 value -->
<li v-for="item in movies">{{ item }}</li>
</ul>
<ul>
<!-- key 屬性名 -->
<!-- item 屬性值 -->
<li v-for="(item,key) in movies">{{ key }}-{{ item }}</li>
</ul>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
movies:{
id: 1,
name: '動物世界',
actor: '李易峯',
time: '2018-05-04'
}
}
}
})
</script>
組件的key屬性
- 官方推薦使用v-for是,給對應的元素或者組件添加上一個key屬性
- 爲什麼要使用key屬性呢?
- 這個其實和Vue的Diff算法有關係
- 當某一層有很多相同的節點時,也就是列表節點是,我們希望插入一個新的節點
- 我們希望在b和c之間插入f,Diffy算法執行起來是這樣的。
- 即把D更新成C,E更新成D,最後再插入E,這樣做效率不太高
- 所以我們需要使用key來給每一個節點做一個唯一標識
- Diff算法就可以正確的識別此節點
- 找到正確的位置插入新的值
- key的作用是爲了高效的更新虛擬DOM
數組中的響應式方法
1 push()
2 pop()
3 shift()
4 unshift()
5 splice()
6 sort()
7 reverse()
8 Vue中的set方法
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in letter" :key="item">{{ item }}</li>
</ul>
<button type="button" @click="btnClick">按鈕</button>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
letter: ['A', 'B', 'C', 'D', 'E'],
nums: [1, 3, 4, 77, 33, 6]
}
},
methods: {
btnClick() {
// 1 push()
// 在數組後添加一個元素
// Math.random().toString(36).substr(2) 隨機生成字母和數字的組合
this.letter.push(Math.random().toString(36).substr(2));
// 一次添加多個元素
this.letter.push('aaa', 'bbb', 'ccc');
// 2 pop()
// 刪除數組的最後一個元素
this.letter.pop();
// 3 shift()
// 刪除數組的第一個元素
this.letter.shift();
// 4 unshift()
// 在數組最前面添加一個元素
this.letter.unshift(Math.random().toString(36).substr(2));
// 5 splice()
// splice方法可以刪除元素/插入元素/替換元素
// 刪除
this.letter.splice(1, 2);
// splice(1, 2);//從第一個元素開始,向後刪除2個元素 顯示ADE
// 如果沒有傳第二個參數就刪除從起始位置後的所有元素
// 替換
// 顯示AFGHI
// 從第一個元素開始,向後替換四個元素
this.letter.splice(1, 4, 'F', 'G', 'H', 'I');
// 插入
// 顯示ABCDFGHIE
// 在數組的第四個元素後添加'F', 'G', 'H', 'I'
this.letter.splice(4, 0, 'F', 'G', 'H', 'I');
// 6 sort()
// 數組的排序
// 打印輸出 [1, 3, 33, 4, 6, 77]
console.log(this.nums.sort());
// 7 reverse()
// 翻轉數組
// 顯示EDCBA
this.letter.reverse();
// 8 Vue中的set方法
// set(要修改的對象, 索引值, 修改後的值)
// 顯示 bbb B C D E
Vue.set(this.letter, 0, 'bbbb')
// 注意:通過索引值,更改數組中的元素,這個不是響應式的
// this.letter[0] = 'bbb';
// 使用可變參數(...)的函數
// function add(...num) {
// // 打印輸出[1, 2, 3, 4, 4, 5, 5]
// console.log(num);
// }
// add(1, 2, 3, 4, 4, 5, 5);
}
}
})
</script>
</body>
</html>
階段案例(圖書購物車)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
table {
border: 1px solid #e9e9e9;
border-collapse: collapse;
border-spacing: 0;
}
th,
td {
padding: 8px 16px;
border: 1px solid #E9E9E9;
text-align: center;
}
th {
background-color: #7F7F7F;
color: #5c6b77;
font-weight: 600;
}
</style>
</head>
<body>
<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th>編號</th>
<th>書籍名稱</th>
<th>出版日期</th>
<th>價格</th>
<th>購買數量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in books">
<!-- 一次顯示所有,不宜於做其他操作 -->
<!-- <td v-for="value in item">{{ value }}</td> -->
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.data }}</td>
<!-- 1 使用toFixed直接保留小數 -->
<!-- <td>{{ '¥' + item.price.toFixed(2) }}</td> -->
<!-- 2 通過函數的封裝調用保留小數 -->
<!-- <td>{{ getFinalPrice(item.price) }}</td> -->
<!-- 3 過濾器 -->
<td>{{ item.price | getFinalPrice }}</td>
<td>
<button type="button" @click="increment(index)">+</button>
{{ item.count }}
<button type="button" @click="decrement(index)" :disabled="item.count <= 1">-</button>
</td>
<td>
<button type="button" @click="removeHandel(index)">移出</button>
</td>
</tr>
</tbody>
</table>
<h2>總價格:{{ totalPrice | getFinalPrice }}</h2>
</div>
<div v-else>
<h2>購物車爲空</h2>
</div>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
</script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
books: [{
id: 1,
name: '《算法導論》',
data: '2006-9',
price: 85.00,
count: 1
}, {
id: 2,
name: '《計算機概論》',
data: '2018-9',
price: 35.00,
count: 1
}, {
id: 3,
name: '《網絡技術與基礎》',
data: '2006-9',
price: 84.00,
count: 1
}, {
id: 4,
name: '《編程珠璣》',
data: '2008-9',
price: 39.00,
count: 1
}, {
id: 5,
name: '《代碼大全》',
data: '2006-9',
price: 85.00,
count: 1
}]
}
},
computed: {
totalPrice() {
// 1 普通的for循環
// let total = 0;
// for (let i = 0; i < this.books.length; i++) {
// total += this.books[i].price * this.books[i].count;
// }
// return total;
// 2 es6中的for let in循環
// let total = 0;
// for (let i in this.books) {
// // console.log(i); i是數組的索引
// total += this.books[i].price * this.books[i].count;
// }
// return total;
// 3 es6中拿到數組中每一項的索引值
// let total = 0;
// for (let item of this.books) {
// // item 是數組中每一項的值
// // console.log(s);
// total += item.price * item.count;
// }
// return total;
// 高階函數reduce
return this.books.reduce(function(preVaule, book) {
return preVaule + book.price * book.count;
}, 0);
}
},
methods: {
// 保留小數 函數
// getFinalPrice(price) {
// return '¥' + price.toFixed(2)
// }
// 加法函數
increment(index) {
// console.log('increment',index);
this.books[index].count++
},
// 減法函數
decrement(index) {
// console.log('decrement',index);
this.books[index].count--
},
removeHandel(index) {
this.books.splice(index, 1)
}
},
// 過濾器
filters: {
getFinalPrice(price) {
return '¥' + price.toFixed(2)
}
}
})
</script>
</body>
</html>
高階函數(filter,map,reduce)
- 去除所有小於100的數組
- 將所有小於100的數組轉成: 全部乘以2
- 將所有new2Num的數字相加,得到最終的結果
普通js實現:
const num = [10, 20, 30, 40, 50, 200];
// 創建一個空數組
let newNum = [];
// 1 通過for循環將所有小於100的數據,添加到新數組中
for (let s of num) {
if (s < 100) {
newNum.push(s)
}
}
// 創建一個空數組
let new2Num = [];
// 2 通過for循環遍歷1中得到的小於100的數據,將1中的數組的每一項都乘以2
for (let n of newNum) {
new2Num.push(n * 2);
}
console.log(new2Num);
// 3 遍歷2中得到的數組,將數組中每項值相加
let total = 0;
for (let n of new2Num) {
console.log(total += n);
}
通過高階函數實現:
const num = [10, 20, 30, 40, 50, 200];
// 高階函數
// 1 過濾
// filter函數 必須返回一個布爾值
// 當函數返回true時,函數內部會自動將這次回調的n加入到新的數組中
// 當函數返回false時,函數內部會過濾掉不符合條件的n
let newNum = num.filter(function(n) {
// console.log(n); //filter函數會回調6次
return n < 100;
});
console.log(newNum); //打印輸出[10, 20, 30, 40, 50]
// 2 map
let new2Num = newNum.map(function(n) {
return n * 2;
});
console.log(new2Num); //打印輸出[20, 40, 60, 80, 100]
// 3 reduce
// 作用: 對數組中所有的值進行彙總
// preVaule 上一次遍歷返回的值
// 第一次:preVaule: 0 n: 20
// 第二次: preVaule: 第一次返回的值 n: 40
let total = new2Num.reduce(function(preVaule, n) {
return preVaule + n;
}, 0);
console.log(total); // 打印輸出300
簡化高階函數:
const num = [10, 20, 30, 40, 50, 200];
let total = num.filter(function(n) {
return n < 100;
}).map(function() {
return n * 2;
}).reduce(function(preVaule, n) {
return preVaule + n;
}, 0);
console.log(total);
高階函數和es6簡化:
let total = num.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
console.log(total);
v-mode(數據的雙向綁定)
-
表單控件在實際開發中是非常常見的,特別是對於用戶信息的提交,需要大量的表單
-
Vue中使用v-model指令來實現表單元素和數據的雙向綁定
<div id="app"> <input type="text" v-model="message" /> <h2>{{ message }}</h2> <!-- v-model的實現原理 --><!-- v-on:input監聽用戶輸入的事件 --> <!-- 1 v-bind綁定value屬性 --> <!-- 2 v-on指令給當前元素綁定input事件 --> <input type="text" :value="name" @input="valueChange"/> <input type="text" :value="name" @input="name = $event.target.value"/> <h2>{{ name }}</h2> </div> <script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '#app', data() { return { message: 'hello xiaochen', name: 'Heray' } }, methods: { valueChange(event) { this.name = event.target.value; } } }) </script>
v-model:radio(單選框)
<div id="app">
<label for="male">
<!-- 單選按鈕只能選擇一個 添加name屬性 或者 v-model屬性-->
<input type="radio" id="male" name="sex" value="男" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" name="sex" value="女" v-model="sex">女
</label>
<h2>你選擇的性別是:{{ sex }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
// 給sex添加值,讓頁面加載的時候默認選中男
sex: '男'
}
}
})
</script>
v-model:checkbox(複選框【單個複選框,多個複選框】)
<div id="app">
<!-- 1 checkbox單選框 -->
<label for="agreement">
<input type="checkbox" id="agreement" v-model="isAgreement" />同意協議
</label>
<h2>你的選擇是: {{ isAgreement }}</h2>
<!-- 只有統一協議才能下一步,isAgreement爲false時下一步按鈕是禁用的狀態 -->
<button type="button" :disabled="!isAgreement">下一步</button>
<hr />
<input type="checkbox" value="籃球" v-model="hobbies">籃球
<input type="checkbox" value="滑冰" v-model="hobbies">滑冰
<input type="checkbox" value="街舞" v-model="hobbies">街舞
<input type="checkbox" value="唱歌" v-model="hobbies">唱歌
<input type="checkbox" value="滑板" v-model="hobbies">滑板
<h2>你的愛好是:{{ hobbies }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
// 單選框對應的是一個布爾值
isAgreement: false,
// 多選框對應的是一個數組
hobbies: []
}
}
})
</script>
v-model:select(一個,多個)
<div id="app">
<!-- 1 選擇一個 -->
<select name="selected" v-model="fruit">
<option value="蘋果">蘋果</option>
<option value="香蕉">香蕉</option>
<option value="梨子">梨子</option>
<option value="櫻桃">櫻桃</option>
<option value="草莓">草莓</option>
<option value="車釐子">車釐子</option>
</select>
<h2>你喜歡的水果是:{{ fruit }}</h2>
<hr />
<!-- 2 選擇多個 -->
<select name="selected" v-model="fruits" multiple="multiple">
<option value="蘋果">蘋果</option>
<option value="香蕉">香蕉</option>
<option value="梨子">梨子</option>
<option value="櫻桃">櫻桃</option>
<option value="草莓">草莓</option>
<option value="車釐子">車釐子</option>
</select>
<h2>你喜歡的水果是:{{ fruits }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
fruit:'草莓',
fruits:[]
}
}
})
</script>
值綁定
<div id="app">
<label v-for="(item, index) in hobbies" :for="index">
<input type="checkbox" :value="item" :id="index" v-model="hobbies">{{ item }}
</label>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
hobbies: ['街舞', 'rapper', '滑板', '拉丁']
}
}
})
</script>
修飾符
lazy修飾符:
- 默認情況下,v-model默認是在input時間中同步輸入框的數據的
- 一般來說,就是一旦有數據發生改變對應的data中的數據就會自動發生改變
- lazy修飾符可以讓數據在失去焦點或者回車時纔會更新
number修飾符:
- 默認情況下,在輸入框中無論我們輸入的師叔祖還是字母,都會被當作字符串類型進行處理
- 但如果我們希望處理的是數字類型,那麼最好直接將內容當作數字處理
- number修飾符可以讓輸入框中輸入的內容自動轉成數字類型
trim修飾符:
- 如果用戶輸入的內容首尾有跟多空格,通常我們希望去掉
- trim修飾符可以過濾內容左右兩邊的空格
<div id="app">
<!-- 1 lazy修飾符 -->
<!-- 在失去焦點和回車後更新綁定的數據 -->
姓名:<input type="text" v-model.lazy="name"/>
<h2>{{ name }}</h2>
<!-- 2 number修飾符 -->
<!-- 不管怎麼輸入,都只顯示number類型的數據 -->
<!-- <input type="number" v-model="age"/>輸入的是數字,但是顯示出來的數據是string類型的 -->
年齡:<input type="text" v-model.number="age"/>
<h2>{{ age }}-{{ typeof age }}</h2>
<!-- 3 trim修飾符 -->
<!-- 去除輸入內容的前後空格 -->
愛好:<input type="text" v-model.trim="hobby"/>
<h2>{{ hobby }}</h2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
name: 'xiaochen',
age: 18,
hobby: ''
}
}
})
</script>
組件開發
什麼組件化?
一個完成的頁面分成很多個組件,每個組件都用於實現頁面的一個功能塊,每個組件又能進行細分
Vue組件化思想
- 它提供了一種抽象,讓我們可以開發出一個個獨立可複用的小組件來構造我們的應用
- 任何應用都會被抽象成一顆組件樹
- 數據結構:數組/棧/堆/樹結構
組件化思想的應用:
- 有了組件化的思想,我們在之後的開發中就要充分的利用它
- 儘可能的將頁面拆分成一個個小的,可複用的組件
- 這樣讓我們的代碼更加方便組織和管理,並且擴展性也更強
註冊組件的基本步驟
組件的使用分成三個步驟:
- 創建組件構造器
- 註冊組件
- 使用組件
<div id="app">
<!-- 3 使用組件 -->
<my-info></my-info>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 創建組件構造器對象
const cnp = Vue.extend({
// 自定義組件的模板
template: `
<div>
<h2>標題</h2>
<p>內容</p>
<p>尾部</p>
</div>
`
})
<!-- // 2 註冊組件 -->
//Vue.component('註冊組件的標籤名',組件構造器名)
Vue.component('my-info',cnp)
new Vue({
el: '#app',
data() {
return {
}
}
})
</script>
全局組件和局部組件
<div id="app">
<!-- 3 使用全局組件 -->
<my-info></my-info>
<!-- 使用局部組件 -->
<cpns></cpns>
</div>
<div id="app2">
<!-- 使用全局組件 -->
<my-info></my-info>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 創建組件構造器對象
const cnp = Vue.extend({
template: `
<div>
<h2>標題</h2>
<p>內容</p>
<p>尾部</p>
</div>
`
})
<!-- // 2 註冊組件(全局組件,意味着可以在多個Vue的實力下面使用) -->
Vue.component('my-info',cnp)
new Vue({
el: '#app',
data() {
return {
}
},
<!-- 自定義局部組件,局部組件只能在掛載點範圍之內使用 -->
components: {
<!-- cpns使用組件的標籤名 -->
cpns: cnp
}
})
new Vue({
el:'#app2'
})
</script>
父組件和子組件
<div id="app">
<!-- <dad></dad> -->
<brother></brother>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 第一個組件構造器
const dad = Vue.extend({
template:
`
<div>
<h2>頭部</h2>
<div>身體</div>
<div>腳部</div>
</div>
`
})
<!-- // 第二個組件構造器 -->
const brother = Vue.extend({
template:
`
<div>
<h2>head</h2>
<div>body</div>
<div>foot</div>
<dad></dad>
</div>
`,
components: {
<!-- 在brother組件裏面使用dad組件裏面的內容 -->
<!-- 然後使用brother組件,就可以顯示brother組件和dad組件的內容 -->
<!-- 要想使用組件必須註冊組件 -->
<!-- 組件名:組件模板 -->
dad: dad
}
})
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- dad: dad, -->
brother: brother
}
})
</script>
註冊組件的語法糖
<div id="app">
<!-- 全局組件 -->
<daD></daD>
<!-- 局部組件 -->
<cpn2></cpn2>
</div>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 註冊全局組件
const dad = Vue.component('dad', {
template:
`
<div>
<h2>我是dad模板中全局組件的內容</h2>
</div>
`
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 註冊局部組件 -->
'cpn2': {
template:
`
<div>
<h2>我是dad模板中局部組件的內容</h2>
</div>
`
}
}
});
</script>
模板的分離寫法
模板的分離寫法:
<div id="app">
<!-- 全局組件 -->
<daD></daD>
<!-- 局部組件 -->
<cpn2></cpn2>
</div>
<!-- 1 通過script標籤提取模板 -->
<!-- 注意類型必須是:text/x-template -->
<script type="text/x-template" id="dad">
<div>
<h2>我是dad模板中全局組件的內容</h2>
</div>
</script>
<!-- 2 通過template標籤 -->
<template id="cpn2">
<div>
<h2>我是dad模板中局部組件的內容</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 註冊全局組件
const dad = Vue.component('dad', {
// 通過id引用模板
template: `#dad`
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 註冊局部組件 -->
'cpn2': {
template:`#cpn2`
}
}
});
</script>
組件可以訪問Vue實例數據
- 組件是一個單獨功能模塊的封裝:
- 這個模塊有屬於自己的HTML模板,也應該有屬性自己的數據data
- 組件裏面是不能訪問vue實例裏面的數據的。
組件數據的存放:
- 組件對象也有一個data屬性(也可以有methods等屬性)
- 只是這個data屬性必須是一個函數
- 而且這個函數返回一個對象,對象內部保存着數據
<div id="app">
<!-- 全局組件 -->
<daD></daD>
<!-- 局部組件 -->
<cpn2></cpn2>
</div>
<!-- 1 通過script標籤提取模板 -->
<!-- 注意類型必須是:text/x-template -->
<script type="text/x-template" id="dad">
<div>
<h2>{{ message }}</h2>
</div>
</script>
<!-- 2 通過template標籤 -->
<template id="cpn2">
<div>
<h2>{{ message }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 註冊全局組件
const dad = Vue.component('dad', {
// 通過id引用模板
template: `#dad`,
data() {
return {
message: '我是dad模板中全局組件的內容'
}
}
});
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
<!-- 註冊局部組件 -->
'cpn2': {
template: `#cpn2`,
data() {
return {
message: '我是dad模板中局部組件的內容'
}
}
}
}
});
</script>
組件中的數據存放爲什麼是一個函數(面試可能會問)
函數每次都會返回一個新的新的對象,產生不同的數據。
對象每次都作用在一個屬性上,一個改變所有的都改變({}可能會相互影響)。
<div id="app">
<cpn></cpn>
<cpn></cpn>
</div>
<!-- 組件模板 -->
<template id="cpn">
<div>
<h2>當前計數:{{ num }}</h2>
<button type="button" @click="increment">+</button>
<button type="button" @click="decrement">-</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 1 註冊組件
Vue.component('cpn', {
template: `#cpn`,
// data是一個函數,函數每次都會返回一個新的對象
// 這樣同時使用一個組件,點擊一個組件,就不會改變其他組件的值
// 如果data {} 返回的是一個對象,每次作用的都是一個同養的對象,一個改變其他的都改變
// 使用{},會產生連鎖反應
data() {
return {
num: 0
}
},
methods: {
increment() {
this.num++
},
decrement() {
this.num--
}
}
})
const app = new Vue({
el: '#app',
data() {
return {
}
}
})
</script>
父子組件的通信
通信:相互交流,數據傳遞。在大組件(父組件)獲取所有的後臺數據,然後在傳遞給小組件(子組件),渲染到頁面。
如何進行父子組件的通信?
- 通過props(是
properties
屬性的縮寫)向子組件中傳遞數據 - 通過自定義事件向父組件發送消息
父傳子props
<div id="app">
<!-- 在父組件裏面使用子組件 -->
<!-- 在頁面中顯示[ "速度與激情", "肖申克的救贖", "友情之上", "摩登少年" ] 和 hello -->
<cpn v-bind:cmovies="movies" :cmessage="message"></cpn>
<!-- 在傳值後,如果沒有用v-bind,則會把綁定字段,當成字符串解析 -->
<!-- 在頁面中顯示movies message -->
<cpn cmovies="movies" cmessage="message"></cpn>
</div>
<template id="cpn">
<div>
<p>{{ cmovies }}</p>
<!-- 循環遍歷父組件中傳遞過來的數據 -->
<ul>
<li v-for="item in cmovies">{{ item }}</li>
</ul>
<h2>{{ cmessage }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 自定義組件
const cpn = {
template: `#cpn`,
// 父傳子props
// 1 數組
props: ['cmovies','cmessage'],
// 2 對象
prpos: {
// 1 類型的限制
// cmovies: Array,
// cmessage: String
// 2 提供一些默認值,以及必傳值
cmessage: {
type: String,
// 沒有傳值提供的默認值
default: 'aa',
// 傳值時cmessage是必須傳的值
required: true
},
cmovies: {
type: Array,
// 類型是對象或者數組時,默認值必須是一個函數
default() {
return []
}
}
}
}
const app = new Vue({
el: '#app',
data() {
return {
message: 'hello',
movies:['速度與激情', '肖申克的救贖', '友情之上', '摩登少年']
}
},
components: {
cpn
}
})
</script>
props數據驗證
驗證支持的數據類型:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
- 自定義數據類型
Vue.component('my-component',{
props: {
//基礎的類型檢查(null,匹配任何數)
propA: Number,
//多個可能的類型
propB: [String, Number],
//必填的字符
propC: {
type: String,
required: true
},
//帶有默認值的數字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
default() {
// 返回一個默認值
return { message:'hello' }
}
},
// 自定義驗證函數
propF: {
validator(value){
//這個值必須匹配下列字符中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
自定義數據類型:
function Person(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
}
Vue.component('blog-post', {
props: {
// 自定義數據類型
author: Person
}
})
props中的駝峯標識
在子組件中,props中的數據使用了駝峯命名,在父組件中使用必須去掉駝峯(遇到大寫字母在前面加-分隔,然後將大寫字母變成小寫字母)
<div id="app">
<!-- 子組件是在父組件中有使用的 -->
<!-- 在子組件上綁定(v-bind)父組件傳遞過來的數據 -->
<!-- v-bind不支持駝峯命名 -->
<!-- <cpn :cinfo = "info"></cpn> -->
<!-- props中綁定的數據是cInfo,使用了駝峯必須 -->
<!-- 使用是必須將 cInfo 寫成 c-info-->
<!-- 遇到大寫字母在前面加-,然後將其變成小寫使用 -->
<cpn :c-info = "info"></cpn>
</div>
<template id="cpn">
<!-- 子組件的模板中有很多個標籤,必須有一個跟標籤將其包裹 -->
<div>
<!-- 使用父組件中傳遞過來的數據 -->
<!-- <h2>{{ cinfo }}</h2> -->
<!-- props中使用了駝峯 -->
<!-- 在頁面中顯示 { "name": "蕭辰", "age": 18, "hobbie": [ "街舞", "吉他", "滑板" ] } -->
<h2>{{ cInfo }}</h2>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 子組件
const cpn = {
template: `#cpn`,
props: {
// cinfo: {
cInfo: {
type:Object,
default() {
return {
}
}
}
}
};
// 父組件
const app = new Vue({
el: '#app',
data() {
return {
info: {
name: '蕭辰',
age: 18,
hobbie: ['街舞', '吉他', '滑板']
}
}
},
components: {
cpn
}
})
</script>
子組件向父組件中傳遞數據(自定義事件)
自定義事件的流程:
- 在子組件中,通過$emit()來觸發時間
- 在父組件中,通過v-on來監聽子組件事件
<!-- 父組件模板 -->
<div id="app">
<!-- 監聽v-bind子組件發射出的時間 -->
<!-- 子組件監聽子組件傳遞過來的事件時綁定的事件不能使用駝峯命名 -->
<!-- cpnClick(item) 寫成 cpnClick這樣也是可以的,從子組件傳遞過來的方法,會默認將參數也傳遞過來,就像event一樣-->
<cpn @itemclick="cpnClick(item)"></cpn>
</div>
<!-- 子組件模板 -->
<template id="cpn">
<div>
<button v-for="item in cartegories" @click="btnClick(item)">{{ item.name }}</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 子組件
const cpn = {
template: '#cpn',
data() {
return {
cartegories:[
{
id: 'a',
name: '熱門推薦'
},
{
id: 'b',
name: '手機數碼'
},{
id: 'c',
name: '家用家電'
},{
id: 'd',
name: '手機辦公'
},{
id: 'e',
name: '精選服飾'
}
]
}
},
methods: {
btnClick(item) {
// 查看用戶點擊的信息
// console.log(item);
// 將用戶點擊的信息傳到父組件中
// 向父組件中發射自定義事件事件,及傳遞的參數
this.$emit('itemclick', item)
}
}
}
// 父組件
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn
},
methods: {
// 父組件事件
cpnClick(item) {
console.log(item);
}
}
})
</script>
父子組件通信實例
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div id="app">
<cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn>
</div>
<!-- 子組件模板 -->
<template id="cpn">
<div>
<h2>props1:{{ number1 }}</h2>
<h2>data:{{ cnumber1 }}</h2>
<!-- <input type="text" v-model="cnumber1"/> -->
<input type="text" :value="cnumber1" @input="num1Input" />
<h2>props2:{{ number2 }}</h2>
<h2>data:{{ cnumber2 }}</h2>
<!-- <input type="text" v-model="cnumber2"/> -->
<input type="text" :value="cnumber2" @input="num2Input" />
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
num1: 1,
num2: 0
}
},
methods: {
num1change(value) {
this.num1 = parseInt(value);
},
num2change(value) {
this.num2 = parseInt(value);
}
},
components: {
cpn: {
template: `#cpn`,
props: {
number1: Number,
number2: Number
},
data() {
return {
cnumber1: this.number1,
cnumber2: this.number2
}
},
methods: {
num1Input(event) {
// 1 將input中的value賦值到cnumber1
this.cnumber1 = event.target.value;
// 2 爲了讓父組件可以修改值,發出一個事件
this.$emit('num1change', this.cnumber1);
// 3 同時修改cnumber2的值
this.cnumber2 = this.cnumber1 * 100;
this.$emit('num2change', this.cnumber2)
},
num2Input(event) {
this.cnumber2 = event.target.value;
this.$emit('num2change', this.cnumber2);
// 3 同時修改cnumber2的值
this.cnumber1 = this.cnumber2 / 100;
this.$emit('num1change', this.cnumber1)
}
}
}
}
})
</script>
</body>
</html>
父子組件的訪問方式
父組件訪問子組件refs
-
$children 得到的是一個 數組
this.$children[].訪問對象
-
$refs 得到的是一個 對象
this.$refs.添加ref的數值.訪問對象
-
實例
<div id="app">
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button type="button" @click="btnClick">點我</button>
</div>
<template id="cpn">
<div>
我是子組件
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
}
},
methods: {
btnClick() {
// 1 通過$children去拿子組件中的值
// // 拿到的子組件是一個數組類型的
// // console.log(this.$children);
// // 通過$children調用子組件的showMessage方法
// // this.$children[0].showMessage();
// // this.$children[0].name;
// for (let c of this.$children) {
// // 打印輸出showMessage
// c.showMessage();
// // 打印輸出xiaochen
// console.log(c.name);
// }
// 2 通過$refs去拿子組件中的值
// this.$refs默認是一個空對象
console.log(this.$refs);
// 要使用$refs取值,需要在標籤上面添加ref屬性,然後通過this.$refs.ref屬性值拿值
// 打印輸出 showMessage
this.$refs.aaa.showMessage();
// 打印輸出 xiaochen
console.log(this.$refs.aaa.name);
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: 'xiaochen'
}
},
methods: {
showMessage() {
console.log('showMessage');
}
}
}
}
})
</script>
子組件訪問父組件root
-
$parent
this.$parent.訪問父組件的屬性
-
$root
// 訪問根組件,Vue實例 this.$root
實例:
<div id="app">
<cpn>
</cpn>
</div>
<template id="cpn">
<div>
<h2>我是cpn組件</h2>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<h2>我是子組件</h2>
<button @click="btnClick">按鈕</button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
name: '我是cpn組件的name'
}
},
components: {
ccpn: {
template: `#ccpn`,
methods: {
btnClick() {
// 1 訪問父組件$parent
// 打印出來是一個VueComponent對象
console.log(this.$parent);
// 打印輸出 我是cpn組件的name
console.log(this.$parent.name);
// 2 訪問根組件$root
// 打印Vue 實例
console.log(this.$root);
}
}
}
}
}
}
})
</script>
插槽slot(組件化高級)
爲什麼使用組件的插槽:
- 爲了讓我們封裝的組件更加具有擴展性
- 讓使用者可以決定組件內部的一些內容到底展示什麼
插槽的基本使用
使用slot插槽,佔據位置,在使用的時候傳入對應的值,然後傳入的值自己會填補插槽佔據的位置。
插槽的基本使用:
- 插槽的基本使用
- 插槽的默認值
- 如果有多個值,同時放入組件進行替換時,一起作爲替換元素
<div id="app">
<cpn></cpn>
<hr />
<cpn>
<button type="button">點我</button>
</cpn>
<hr />
<cpn><b>我是傳入值</b></cpn>
</div>
<template id="cpn">
<div>
<h2>我是組件</h2>
<slot></slot>
<h5>content</h5>
<!-- 給插槽添加一個默認值,調用的時候沒有加別的參數,就使用默認值,有參數,就是用傳遞的值 -->
<slot><button>我是插槽傳遞的默認值</button></slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`
}
}
})
</script>
如何封裝插槽
抽取共性,保留不同。
- 最好的方式就是將共性抽取到組件中,將不同暴露爲插槽
- 一旦預留了插槽,就可以讓使用者根據自己的需求,決定插槽中插入什麼內容
- 是搜索框,還是文字,還是菜單,由調用者自己來決定
具名插槽
給插槽設置name值,然後使用的使用根據solt等於的name值進行替換。
<div id="app">
<cpn>
<!-- 替換name爲center插槽 -->
<h1 slot="center">標題</h1>
</cpn>
</div>
<template id="cpn">
<div>
<slot name="left">
<h2>我是左邊插槽</h2>
</slot>
<slot name="center">
<h2>我是中間插槽</h2>
</slot>
<slot name="right">
<h2>我是右邊插槽</h2>
</slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
}
},
components: {
cpn: {
template: `#cpn`
}
}
})
</script>
編譯的作用域
父模板的所有東西都會在父級作用域內編譯,子組件模板的所有東西都會在自己作用域內編譯。
<div id="app">
<!-- 這個是根據實例裏面的isShow來決定的 -->
<!-- 命令使用時不關心組件的位置,只關心作用域 -->
<!-- 顯示 app的data中的isShow是true -->
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是子組件</h2>
<!-- 不顯示 -->
<!-- cpn組件中的isShow是false -->
<button v-show="isShow"></button>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
isShow: true
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
isShow: false
}
}
}
}
})
</script>
作用域插槽
作用域插槽的目的就是:
父組件替換插槽的標籤,但是內容由子組件來提供。
實例:
-
子組件中包括一組數據,比如:pLanguages[‘Javascript’, ‘Python’, ‘Swift’, ‘Go’, ‘C++’]
-
需要在多個界面進行展示:
- 某些界面是以水平方向——展示的
- 某些界面是以列表形式展示的
- 某些界面直接展示——一個數組
-
內容在子組件,希望父組件告訴我們如何展示?
- 利用slot插槽就可以了
<div id="app">
<!-- 子組件默認展示 -->
<cpn></cpn>
<!-- 拿到子組件中的數據,然後在父組件中展示成不同的樣式 -->
<!-- 目的:獲取子組件中的pLanguages -->
<cpn>
<template slot-scope="slot">
<!-- 通過slot引用插槽對象 -->
<!-- 通過slot.data 拿到的就是 子組件中傳遞的:data="pLanguages" -->
<span v-for="item in slot.data">{{item}} -</span>
<div>{{ slot.data.join(' - ')}}</div>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 這裏data可以爲任何值 -->
<slot :data="pLanguages">
<ul>
<!-- 子組件展示 -->
<li v-for="item in pLanguages">{{ item }}</li>
</ul>
</slot>
</div>
</template>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
const app = new Vue({
el: '#app',
data() {
return {
isShow: true
}
},
components: {
cpn: {
template: `#cpn`,
data() {
return {
pLanguages: ['Javascript', 'Python', 'Swift', 'Go', 'C++']
}
}
}
}
})
</script>
模塊化開發
js原始功能:
- 做表單驗證活動話
- 隨着ajax的出現,前後端開始分離,爲了應對代碼量的與日俱增,將js分成多個js文件來編輯
- 但這種方式依然不能避免一些災難性問題:
- 全局變量同名
- js文件過多,執行順序的問題
- 解決:使用閉包()() ————》代碼不可複用
- 將每一個js文件封裝成一個閉包,在閉包中通過創建空對象,將使用的值存入空對象中,然後return回去
- 在別的js文件使用的時候,通過封裝的閉包名.要使用的對象
常見的模塊化規範:
CommonJS,AMD,CMD,也有ES6中的Modules
CommonJS只是一個規範,CommonJS的實現是node.js。
CommonJS
模塊化的兩個核心:導出(export)和導入(require)
CommonJS的導出:
moule.export = {
name: 'xiaochen',
doit(a, b) {
return a + b;
}
}
CommonJS的導入:
//CommonJS模塊
let { name,doit } = require('moduleA');
//等同於
let m = require('moduleA');
let name = m.name;
...
ES6的模塊化實現
export
export指令用於導出變量:
export let name = 'xiaochen'
export let age = 18
export let dream = 'free'
也可以:
let name = 'xiaochen'
let age = 18
let dream = 'free'
export {
name, age, dream
}
導出函數和類:
export function sum(a, b) {
return a + b;
}
export class Person {
run() {
console.log('想上學的第一天');
}
}
import {sum, Person} from './a.js'
// 實例化類
const p = new Person();
// 調用類裏面的函數
p.run();
export default:
某些情況下,一個模塊包含某個功能,我們並不希望給這個功能命名,而且讓導入這自己來命名
- 這個時候就可以使用
export default
- 注意:export default 在同一個模塊中,不允許同時存在多個
const time = '二零二零年四月七日'
// 1
export { time }
// 2
export const time = '二零二零年四月七日'
//要使用上面的數據
import {time} from 'a.js'
// 在一個js中文件中,只能有一個default導出
export default time
import t from 'a.js'
import
export指令導出了模塊對外提供的接口後,我們就可以通過import命令來加載這個對應的模塊了
-
首先我們需要在HTML代碼中引入兩個js文件,並且類型需要設置module
<script src = "info.js" type = "module"></script> <script src = "main.js" type = "module"></script>
-
import指令用於導入模塊內容,比如mian.js的代碼
import {name, age, sex} from './info.js' console.log(name, age, sex);
-
統一全部導入
import * as info from './info.js' console.log(info.name);
webpack
認識webpack
什麼是webpack?
官網:webpack.js.org
從本質上將,webpack是一個現代的JavaScript應用的靜態模塊打包工具。
- 靜態
- 打包
和grunt/gulp的對比
- grunt/gulp的核心是Task
- 我們可以配置一系列的task,並且定義task要處理的事物(例如ES6,ts轉換,圖片的壓縮,scss轉化成css)
- 之後讓grunt/gulp來依次執行這些task,而且讓它流程自動化
- grunt/gulp也被稱爲前端自動化任務管理工具
- 什麼時候用到grunt/gulp
- 如果工程模塊依賴非常簡單,甚至是沒有用到模塊化的概念
- 只要進行簡單的合併,壓縮,就使用grunt/gulp即可
- 但是如果整個項目使用了模塊化管理,而且相互依賴非常強,我們就可以使用更加強大的webpack
- gulp和webpack的區別
- grunt/gulp更加強調的是前端流程的自動化,模塊化不是它的核心
- webpack更加強調模塊化開發管理,而文件壓縮合並,預處理功能,是他附帶的功能
webpack的安裝
- webpack是基於node.js的
- node爲了可以正常的運行執行很多代碼面必須其中包含很多包
- 在安裝node時,會自動安裝npm(node package manager)
查看node版本:
node -v
全局安裝webpack(這裏我們先制定版本號3.6.0,因爲vue cli2依賴該版本):
-
查看電腦中有沒有安裝過webpack
webpack --version 或者 webpack -v
-
沒有 安裝
全局安裝webpack:
npm install webpack@3.6.0 -g
本地安裝webpack:
--save-dev
是開發時依賴【devDependencies】,項目打包後不需要繼續使用npm install webpack@3.6.0 --save-dev
webpack的起步
文檔解釋:
dist文件 | distribution(發佈) |
---|---|
文件 | 解釋 |
src文件 | 主要文件,一般項目的文件都寫在src這個文件夾裏面 |
打包:
// webpack 打包文件main.js的路徑 打包成dist下面的bundle.js文件
// webpack在打包的時候會自動處理依賴文件
// 所以只需要打包入口文件就好了
webpack ./src/main.js ./dist/bundle.js
webpack的配置
配置webpack讓項目在運行的時候,直接webpack
就可以運行項目,不需要webpack ./src/main.js ./dist/bundle.js
這樣運行
步驟:
-
在項目文件中創建
webpack.config.js
文件 -
給webpack.config.js添加配置
// path 依賴了node中的path包,所以要安裝node中的所有依賴項 // npm init --yes 安裝所有依賴包 // 就會去全局找path cost path = require('path'); module.exports = { // 入口 entry: './src/main/.js', // 出口 output: { // 路徑 path 是絕對路徑 // 動態獲取路徑 path: path.resolve(__dirname, 'dist'), // 文件名 bundle 打包 filename: 'bundle.js' } }
-
pacjage.json中自定義啓動
爲了在命令行工具中能夠 通過 npm run build 運行項目,在package.json文件的script腳本中添加依賴項
讓我們在執行
npm run build
命令的時候來package.json文件中找到webpack當在命令行工具中執行npm run build的時候相當於執行webpack命令,運行的時候num run build會先去查找本地的webpack,這樣防止因webpack版本的問題而引發錯誤
"build": "webpack"
通過
npm run build
打包後的文件是全局的
loader的使用
-
loader是webpack中一個非常核心的概念
-
webpack用來做什麼呢?
- 在我們之前的實例中,我們主要是用webpack來處理我們寫的js代碼,並且webpack會自動處理js之間相關的依賴
- 但是,在開發中我們不僅僅有基本的js代碼處理,我們也需要加載css,圖片,也包括一些高級的將ES6轉成ES5的代碼,將scss,less轉成css,將.jsx,vue文件轉成js文件等等。
- 對於webpack本身的能力來說,對於這些轉化是不支持的
- 那怎麼辦呢?給webpack擴展對應的loader就可以了。
-
loader使用過程:
-
步驟一:通過npm安裝需要使用的loader
-
css-loader
npm install --save-dev css-loader
-
style-loader
npm install --save-dev style-loader
-
-
步驟二:在webpack.config.js中的modules關鍵字下進行配置
在module中css-loader只負責將css文件進行加載,style-loader將樣式添加到DOM中
使用多個loader時,是從右向左
module: { rules: [ { test: /\.css$/ use: ['style-loader', 'css-loader'] } ] }
-
步驟三:配置,也就是再次打包,npm run build
-
less文件處理–準備
要想使用less文件更改樣式要安裝less-loader
:
npm install --save-dev less-loader less
在webpack.config.js文件中配置less:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
}]
}
};
圖片配置
下載url-loader
:
npm install --save-dev url-loader
配置url-loader:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// 當加載的圖片,小於limit時,會將圖片編譯成base64字符串形式
// 當加載的圖片,大於limit時,會使用file-loader模塊進行加載,通過webpack打包後會編譯成base64字符串的形式
limit: 8192 // 8192 8kb
// 打包後webpack自動幫我們生成一個非常長的名字,但真是開發中,我們可能對打包圖片的名字有一定的要求,比圖將所有的圖片放在一個文件夾中,跟圖片原來的名稱,同時也要防止重複
// [name]:圖片原來的名字 [hash:8]:哈希值保留8位 [ext]:圖片的擴展名
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
}
安裝file-loader:
npm install --save-dev file-loader
安裝後,文檔中使用的圖片是打包後dist文件夾中的圖片,
在webpack.config.js文件配置圖片使用的路徑:
在output中加入publicPath
output: {
publicPath: 'dist/'
}
ES6語法處理
ES6的語法直接轉成ES5,需要使用babel。
在webpack中直接使用babel對應的loader就可以了。
安裝:
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件:
env:environment環境的縮寫。
module: {
rules: [
{
test: /\.js$/,
// exclude:排除
// include:包含
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
}
webpack中配置Vue
-
在項目中使用vue.js進行開發,那麼必須對其有依賴,所以我們先要進行安裝:
--save dev
是開發時依賴,因爲我們後續是在實際項目中使用vue的,所以並不是開發時依賴,使用--save
npm install vue --save // 簡寫 npm install vue -S
-
使用vue進行開發
// 導入vue import Vue from 'vue' //使用 new Vue({ el: '#app', ... })
-
vue在發佈的時候,發佈了兩個版本
-
runtime-only
- 代碼中,不可以有任何的template
-
runtime-complier
- 代碼中,可以有template,因爲有complier可以用於編譯template
-
要解決這個問題,只需要在webpack.config.js中配置
resolve: { // 文件引入時省略後綴名配置 extensions: ['.js', '.css', '.vue'], // alias 別名 alias: { // 如果導入vue後,去vue文件中去找vue.esm.js文件,這個文件中包含了complier 'vue$':'vue/dist/vue.esm.js' } }
-
el和template的區別,及vue文件的封裝
-
template在解析的時候會替換el,再去修改html中的代碼
-
但是如果將所有替換的代碼都寫在template裏面,看着就很感覺很複雜,我們可以將template中的信息提取成一個組件
// ------------------------------2.app.js文件------------------------------------ // App對象中的代碼可以封裝到一個app.js文件裏面 export default { template: ` <div> .... </div> `, data() { return { } } ... // 將所有的內容抽取到一個組件裏面使用 } // -----------------------------3.創建App.vue文件-------------------------------- //讓模板於組件分離 <template> <div> .... </div> </template> <script> export default { name: "App", data() { return { } } ... } </script> <style> //樣式 </style> // ------------------------------1.main.js文件------------------------------------ //const App = { // template: // ` // <div> // .... // </div> // `, // data() { // return { // } // } // ... // 將所有的內容抽取到一個組件裏面使用 //} // 引入App組件內容 //import App from './vue/app' import App from './vue/App.vue' new Vue({ el: '#app', template: '<App />', components: { App // 在組件裏面註冊App } })
但是在編譯過程中不能識別App.vue文件,所以我們需要對vue文件進行一個封裝,就要使用
vue-loader
和vue-template-complier
安裝:
vue-loader讓vue文件進行一個加載,vue-template-complier 對vue文件進行編譯
npm install vue-loader vue-template-complier --save-dev
配置:
{ test: /\.vue$/, use: ['vue-loader'] }
因爲vue-loader版本的原因,可能會報錯,說
vue-loader was used without the corresponding plugin
,在package.json文件中將vue-loader
的版本改成^13.0.0
(13到14版本之間),然後在命令行工具中執行npm install
重新安裝一下
plugin
- plugin是什麼?
- plugin是插件的意思,通常是用於對某個現有的框架的進行擴展
- webpack中的插件,就是對webpack現有功能的各種擴展,比如打包優化,文件壓縮等。
- loader和plugin的區別:
- loader主要用於轉換某些類型的模塊,它是一個轉換器
- plugin是插件,它是對webpack本身的一個擴展,是一個擴展器。
- plugin的使用過程:
- 通過npm安裝需要使用的plugins(某些webpack已經內置的插件不需要安裝)
- 在webpack.config.js中的plugins中配置插件
添加版權的plugin
BannerPlugin,屬於webpack自帶的插件。
修改webpack.config.js的文件:
const path = require('path');
//導入webpack
const webpack = require('webpack');
modeule.exports = {
...
plugins: [
new webpack.BannerPlugin('最終版權歸aaa所有')
]
}
重新打包:
npm run build/webpack
打包html的plugin
-
目前,我們的index.html頁面存放在項目的根目錄下
- 在真實發布項目的時候,發佈的是dist文件夾中的內容,但是dist文件夾中如果沒有index.html文件,那麼打包的js文件也就沒有意義了
- 所以我們需要將index.html文件打包到dist文件夾中,這個時候就可以使用HtmlWebpackPlugin插件
-
HtmlWebpackPlugin插件可以:
- 自動生成一個index.html文件(可以指定模板來生成)
- 將打包的js文件,自動通過script標籤插入到body中
-
安裝HtmlWebpackPlugin插件
npm install html-webpack-plugin --save-dev
-
使用插件,修改webpack.config.js文件中plugins部分的內容
-
這裏的template表示根據什麼模板來生成index.html
-
另外我們需要刪除之前在output中添加的publicPath屬性
-
否則插入的script標籤中的src可能會有問題
const path = require('path'); //導入webpack const webpack = require('webpack'); // 導入HtmlWebpackPlugin插件 const HtmlWebpackPlugin = require('html-webpack-plugin'); modeule.exports = { ... plugins: [ new webpack.BannerPlugin('最終版權歸aaa所有'), // 這樣使用之後,就會在文件中的dist文件夾下面生成index.html文件 new HtmlWebpackPlugin({ // 讓template根據index.html文件來生成index.html template: 'index.html' }) ] }
-
js壓縮的Plugin
-
在項目發佈之前,我們必須要對js等文件進行壓縮處理
-
對js文件進行壓縮,使用的是第三方插件
unlifyjs-webpack-plugin
,並且版本號指定1.1.1
,和cli2
保持一致npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
-
-
修改webpack.config.js文件,使用插件:
const path = require('path'); //導入webpack const webpack = require('webpack'); // 導入unlifyjs-webpack-plugin插件 // 在開發階段不建議使用uglifyJsPlugin插件,代碼在修改後不宜調試 const uglifyJsPlugin = require('unlifyjs-webpack-plugin'); module.exports = { ... plugins: [ new webpack.BannerPlugin('最終版權歸aaa所有'), new uglifyJsPlugin() ] }
-
查看打包後的bunlde.js文件,最後已經被壓縮過了
搭建本地服務器
-
webpack提供了一個可選的本地服務器,這個本地服務器基於node.js搭建,內部使用express框架,可實現瀏覽器自動刷新顯示修改後的結果。
-
不過它是一個單獨的模塊,在webpack中使用之前需要先安裝
npm install --save-dev webpack-dev-server@2.9.1
-
devserver也是作爲webpack中的一個選項,選項本身可以設置以下屬性:
- contentBase:爲那個文件提供本地服務,默認是根文件夾,我們這裏要填寫./dist
- port: 端口號
- inline:頁面實時刷新
- historyApiFallback:在SPA頁面中,依賴HTML5的history模式
-
webpack.config.js文件配置修改:
devServer: { contentBase: './dist', inline: true }
-
我們還可以配置package.json中的script:
-
–open參數標識直接打開瀏覽器
"build": "webpack" "dev": "webpack-dev-server --open"
-
配置完成後運行:
在命令窗口通過npm run dev
運行
配置(webpack.config.js)結構分離
將開發時依賴和發佈時依賴分離。
-
在主文件夾下創建build文件夾,在build文件夾下面創建
base.config.js
(公共),prod.config.js
(開發時依賴包)和dev.config.js
(運行時依賴) -
安裝
webpack-merge
,將分離的文件進行合併npm install webpack-merge --save-dev
-
使用
base.config.js中:
const path = require('path'); //導入webpack const webpack = require('webpack'); modeule.exports = { // 入口 entry: './src/main/.js', // 出口 output: { // 路徑 path 是絕對路徑 // 動態獲取路徑 path: path.resolve(__dirname, 'dist'), // 文件名 bundle 打包 filename: 'bundle.js' }, module: { rules: [{ test: /\.css$/ use: ['style-loader', 'css-loader'] }] }, plugins: [ new webpack.BannerPlugin('最終版權歸aaa所有') new HtmlWebpackPlugin({ // 讓template根據index.html文件來生成index.html template: 'index.html' }) ] }
prod.config.js中:
const uglifyJsPlugin = require('unlifyjs-webpack-plugin'); // 導入webpack-merge const webpackMerage = require('webpack-merge'); //拿到baseConfig const baseConfig = require('./base.config'); //將config文件合併導出 module.exports = webpackMerage(baseConfig, { ... plugins: [ new webpack.BannerPlugin('最終版權歸aaa所有'), new uglifyJsPlugin() ] })
dev.config.js中:
// 導入webpack-merge const webpackMerage = require('webpack-merge'); //拿到baseConfig const baseConfig = require('./base.config'); module.exports = webpackMerage(baseConfig,{ devServer: { contentBase: './dist', inline: true } })
最後在使用時候,將package.json文件中的build改爲:
更改一下config的指向:
"build": "webpack --config ./build/prod.config.js", "dev": "webpack-dev-server --open --config ./build/dev.config.js"
然後使用:
run run dev
但是這樣打包後的文件在build文件下面生成的dist文件夾裏面,爲了解決這個問題,就將base.config.js文件中output下的path改爲:
path: path.resolve(__dirname, '../dist')
Vue cli腳手架詳解
什麼是Vue CLI
- CLI是Command-Line Interface,翻譯爲命令行界面,俗稱腳手架
- Vue CLI是官方發佈的vue.js項目腳手架
- 使用vue-cli可以快速搭建Vue開發環境及對應的webpack配置
Vue CLI使用前提-Node
腳手架應用於webpack,webpack基於node。
Vue CLI的使用
-
安裝Vue腳手架,-g(global:全局的)
npm install -g @vue/cli
-
注意:上面安裝的是Vue CLI3的版本,如果需要想按照Vue CLI2的方式初始化項目是不可以的。
安裝Vue CLI2:
npm install -g @vue/cli-init
-
安裝完成後,查看是否安裝成功:
vue --version
-
Vue CLI2初始化項目:
- vue init webpack my-project(項目名稱)
-
Vue CLI3初始化項目
-
vue create my-project
chrome中的 v8引擎(使用c++實現,v8是開源的),將js代碼直接編譯成二進制代碼,在瀏覽器中執行
js -》 瀏覽器
js -》字節碼 -》瀏覽器
-
視頻材料鏈接: https://pan.baidu.com/s/1dxV3TSKpHoFhZo-oM3stFg
提取碼: epuk