Vue.js學習筆記
Vue 的核心庫只關注檢視層,方便與第三方庫或既有專案整合。
HTML + CSS + JS : 檢視 : 給使用者看,重新整理後臺給的資料
網路通訊 : axios
頁面跳轉 : vue-router
狀態管理:vuex
Vue-UI : ICE , Element UI
- VUE 概述
Vue (讀音/vju/, 類似於view)是一套用於構建使用者介面的漸進式框架,釋出於2014年2月。與其它大型框架不同的是,Vue被設計為可以自底向上逐層應用。Vue的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫(如: vue-router: 跳轉,vue-resource: 通訊,vuex:管理)或既有專案整合 - 前端三要素
HTML (結構) :超文字標記語言(Hyper Text Markup Language) ,決定網頁的結構和內容
CSS (表現) :層疊樣式表(Cascading Style sheets) ,設定網頁的表現樣式
JavaScript (行為) :是一種弱型別指令碼語言,其原始碼不需經過編譯,而是由瀏覽器解釋執行,用於控制網頁的行為 - JavaScript框架
jQuery: 大家熟知的JavaScript框架,優點是簡化了DOM操作,缺點是DOM操作太頻繁,影響前端效能;在前端眼裡使用它僅僅是為了相容IE6、7、8;
Angular: Google收購的前端框架,由一群Java程式設計師開發,其特點是將後臺的MVC模式搬到了前端並增加了模組化開發的理念,與微軟合作,採用TypeScript語法開發;對後臺程式設計師友好,對前端程式設計師不太友好;最大的缺點是版本迭代不合理(如: 1代-> 2代,除了名字,基本就是兩個東西;截止發表部落格時已推出了Angular6)
React: Facebook出品,一款高效能的JS前端框架;特點是提出了新概念[虛擬DOM]用於減少真實DOM操作,在記憶體中模擬DOM操作,有效的提升了前端渲染效率;缺點是使用複雜,因為需要額外學習一門[JSX] 語言;
Vue:一款漸進式JavaScript框架,所謂漸進式就是逐步實現新特性的意思,如實現模組化開發、路由、狀態管理等新特性。其特點是綜合了Angular (模組化)和React (虛擬DOM)的優點;
Axios :前端通訊框架;因為Vue 的邊界很明確,就是為了處理DOM,所以並不具備通訊能力,此時就需要額外使用一個通訊框架與伺服器互動;當然也可以直接選擇使用jQuery提供的AJAX通訊功能;
前端三大框架:Angular、React、Vue
ES6語法
1.不一樣的變數宣告:const和let
ES6推薦使用let宣告區域性變數,相比之前的var(無論宣告在何處,都會被視為宣告在函式的最頂部)
let和var宣告的區別:
var x = '全域性變數';
{
let x = '區域性變數';
console.log(x); // 區域性變數
}
console.log(x); // 全域性變數
<body>
<button>按鈕1</button>
<button>按鈕2</button>
<button>按鈕3</button>
<button>按鈕4</button>
<button>按鈕5</button>
<script>
// 變數作用域:變數在什麼位置內是可用的
// ES5之前因為if和for都沒有塊級作用域的概念,所以在很多時候,我們都必須藉助於function的作月域來解決應用外面變數的問題
// 閉包可以解決這個問題: 函式是一個作用域
// ES6中加入了let,let它是有if和for塊級作用域
// ES5語法
// var btns = document.getElementsByTagName('button');
// for(var i = 0; i<btns.length; i++){
// (function(num){
// bnts[num].addEventListener('click',function(){
// console.log('第'+num+'個按鈕被點選');
// })
// })(i)
// }
// ES6語法
const btns = document.getElementsByTagName('button')
for (let i = 1; i < btns.length; i++) {
btns[i].addEventListener('click', function () {
console.log('第' + i + '個按鈕被點選');
})
}
</script>
</body>
let表示宣告變數,而const表示宣告常量,兩者都為塊級作用域;
const 宣告的變數都會被認為是常量,意思就是它的值被設定完成後就不能再修改了,且const定義識別符號時,必須賦值:
建議:在ES6開發中,優先使用const,只有需要改變某一個識別符號的時候才使用let。
const a = 1
a = 0 //報錯
如果const的是一個物件,物件所包含的值(內部屬性)是可以被修改的。抽象一點兒說,就是物件所指向的地址沒有變就行:
const student = { name: 'cc' }
student.name = 'yy';// 不報錯
student = { name: 'yy' };// 報錯
有幾個點需要注意:
- let 關鍵詞宣告的變數不具備變數提升(hoisting)特性
- let 和 const 宣告只在最靠近的一個塊中(花括號內)有效
- 當使用常量 const 宣告時,請使用大寫變數,如:CAPITAL_CASING
- const 在宣告時必須被賦值
2.模板字串
在ES6之前,我們往往這麼處理模板字串:
通過“\”和“+”來構建模板
$("body").html("This demonstrates the output of HTML \
content to the page, including student's\
" + name + ", " + seatNumber + ", " + sex + " and so on.");
而對ES6來說
- 基本的字串格式化。將表示式嵌入字串中進行拼接。用${}來界定;
- ES6反引號(``)直接搞定;
$("body").html(`This demonstrates the output of HTML content to the page,
including student's ${name}, ${seatNumber}, ${sex} and so on.`);
3.箭頭函式(Arrow Functions)
ES6 中,箭頭函式就是函式的一種簡寫形式,使用括號包裹引數,跟隨一個 =>,緊接著是函式體;
箭頭函式最直觀的三個特點。
- 不需要 function 關鍵字來建立函式
- 省略 return 關鍵字
- 繼承當前上下文的 this 關鍵字
// ES5
var add = function (a, b) {
return a + b;
};
// 使用箭頭函式
var add = (a, b) => a + b;
// ES5
[1,2,3].map((function(x){
return x + 1;
}).bind(this));
// 使用箭頭函式
[1,2,3].map(x => x + 1);
細節:當你的函式有且僅有一個引數的時候,是可以省略掉括號的。當你函式返回有且僅有一個表示式的時候可以省略{} 和 return;
4. 函式的引數預設值
在ES6之前,我們往往這樣定義引數的預設值:
// ES6之前,當未傳入引數時,text = 'default';
function printText(text) {
text = text || 'default';
console.log(text);
}
// ES6;
function printText(text = 'default') {
console.log(text);
}
printText('hello'); // hello
printText();// default
5.Spread / Rest 操作符
Spread / Rest 操作符指的是 ...,具體是 Spread 還是 Rest 需要看上下文語境。
當被用於迭代器中時,它是一個 Spread 操作符:
function foo(x,y,z) {
console.log(x,y,z);
}
let arr = [1,2,3];
foo(...arr); // 1 2 3
當被用於函式傳參時,是一個 Rest 操作符:當被用於函式傳參時,是一個 Rest 操作符:
function foo(...args) {
console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
6.二進位制和八進位制字面量
ES6 支援二進位制和八進位制的字面量,通過在數字前面新增 0o 或者0O 即可將其轉換為八進位制值:
let oValue = 0o10;
console.log(oValue); // 8
let bValue = 0b10; // 二進位制使用 `0b` 或者 `0B`
console.log(bValue); // 2
7.物件和陣列解構
// 物件
const student = {
name: 'Sam',
age: 22,
sex: '男'
}
// 陣列
// const student = ['Sam', 22, '男'];
// ES5;
const name = student.name;
const age = student.age;
const sex = student.sex;
console.log(name + ' --- ' + age + ' --- ' + sex);
// ES6
const { name, age, sex } = student;
console.log(name + ' --- ' + age + ' --- ' + sex);
8.物件超類
ES6 允許在物件中使用 super 方法:
var parent = {
foo() {
console.log("Hello from the Parent");
}
}
var child = {
foo() {
super.foo();
console.log("Hello from the Child");
}
}
Object.setPrototypeOf(child, parent);
child.foo(); // Hello from the Parent
// Hello from the Child
9.for...of 和 for...in
for...of 用於遍歷一個迭代器,如陣列:
let letters = ['a', 'b', 'c'];
letters.size = 3;
for (let letter of letters) {
console.log(letter);
}
// 結果: a, b, c
for...in 用來遍歷物件中的屬性:
let stus = ["Sam", "22", "男"];
for (let stu in stus) {
console.log(stus[stu]);
}
// 結果: Sam, 22, 男
10.ES6中的類
ES6 中支援 class 語法,不過,ES6的class不是新的物件繼承模型,它只是原型鏈的語法糖表現形式。
函式中使用 static 關鍵詞定義建構函式的的方法和屬性:
class Student {
constructor() {
console.log("I'm a student.");
}
study() {
console.log('study!');
}
static read() {
console.log("Reading Now.");
}
}
console.log(typeof Student); // function
let stu = new Student(); // "I'm a student."
stu.study(); // "study!"
stu.read(); // "Reading Now."
類中的繼承和超集:
class Phone {
constructor() {
console.log("I'm a phone.");
}
}
class MI extends Phone {
constructor() {
super();
console.log("I'm a phone designed by xiaomi");
}
}
let mi8 = new MI();
extends 允許一個子類繼承父類,需要注意的是,子類的constructor 函式中需要執行 super() 函式。
當然,你也可以在子類方法中呼叫父類的方法,如super.parentMethodName()。
在 這裡 閱讀更多關於類的介紹。
有幾點值得注意的是:
- 類的宣告不會提升(hoisting),如果你要使用某個 Class,那你必須在使用之前定義它,否則會丟擲一個 ReferenceError 的錯誤
- 在類中定義函式不需要使用 function 關鍵詞
1、基本認識vue
- 輕量級,體積小是一個重要指標。Vue.js 壓縮後有只有 20多kb (Angular 壓縮後 56kb+,React 壓縮後 44kb+)
- 移動優先。更適合移動端,比如移動端的 Touch 事件
- 易上手,學習曲線平穩,文件齊全
- 吸取了 Angular(模組化)和 React(虛擬 DOM)的長處,並擁有自己獨特的功能,如:計算屬性
- Vue是一個漸進式的框架可以將Vue作為你應用的一 部分嵌入其中,帶來更豐富的互動體驗。
- 開源,社群活躍度高
- Vue有很多特點和Web開發中常見的高階功能
- 解耦檢視和資料.
- 可複用的元件
- 前端路由技術
- 狀態管理
- 虛擬DOM
下載地址:
- 開發版本
包含完整的警告和除錯模式:https://vuejs.org/js/vue.js
刪除了警告,30.96KB min + gzip:https://vuejs.org/js/vue.min.js - CDN
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
- NPM安裝
初識vue.js
<body>
<div id="app">{{message}}</div> //執行到這裡顯然出對應的HTML
<script src="../js/vue.js"></script>
<script>
//執行這裡建立Vue例項,並且對原HTML進行解析和修改。
//程式設計正規化:宣告式程式設計
const app = new Vue({ //建立Vue例項
el:'#app', //用於指定要掛載的元素
data:{ //定義資料
message:"洛依塵!"
}
})
//元素js的做法(程式設計正規化:指令式程式設計)
// 1.建立div元素,設定id屬性
// 2.定義一個變數叫message
// 3.將message變數放在前面的div元素中顯示
</script>
</body>
MVVM 模式
MVVM 源自於經典的 Model–View–Controller(MVC)模式(期間還演化出了 Model-View-Presenter(MVP)模式,可忽略不計)。MVVM 的出現促進了 GUI 前端開發與後端業務邏輯的分離,極大地提高了前端開發效率。MVVM 的核心是 ViewModel 層,它就像是一箇中轉站(value converter),負責轉換 Model 中的資料物件來讓資料變得更容易管理和使用,該層向上與檢視層進行雙向資料繫結,向下與 Model 層通過介面請求進行資料互動,起呈上啟下作用。
如下圖所示:
簡單畫了一張圖來說明 MVVM 的各個組成部分:
分層設計一直是軟體架構的主流設計思想之一,MVVM 也不例外。
View 層
View 是檢視層,也就是使用者介面。前端主要由 HTML 和 CSS 來構建,為了更方便地展現 ViewModel 或者 Model 層的資料,已經產生了各種各樣的前後端模板語言,比如 FreeMarker、Marko、Pug、Jinja2等等,各大 MVVM 框架如 KnockoutJS,Vue,Angular 等也都有自己用來構建使用者介面的內建模板語言。
Model 層
Model 是指資料模型,泛指後端進行的各種業務邏輯處理和資料操控,主要圍繞資料庫系統展開。後端的處理通常會非常複雜
ViewModel 層
ViewModel 是由前端開發人員組織生成和維護的檢視資料層。在這一層,前端開發者對從後端獲取的 Model 資料進行轉換處理,做二次封裝,以生成符合 View 層使用預期的檢視資料模型。需要注意的是 ViewModel 所封裝出來的資料模型包括檢視的狀態和行為兩部分,而 Model 層的資料模型是隻包含狀態的,比如頁面的這一塊展示什麼,那一塊展示什麼這些都屬於檢視狀態(展示),而頁面載入進來時發生什麼,點選這一塊發生什麼,這一塊滾動時發生什麼這些都屬於檢視行為(互動),檢視狀態和行為都封裝在了 ViewModel 裡。這樣的封裝使得 ViewModel 可以完整地去描述 View 層。由於實現了雙向繫結,ViewModel 的內容會實時展現在 View 層,這是激動人心的,因為前端開發者再也不必低效又麻煩地通過操縱 DOM 去更新檢視,MVVM 框架已經把最髒最累的一塊做好了,我們開發者只需要處理和維護 ViewModel,更新資料檢視就會自動得到相應更新,真正實現資料驅動開發。看到了吧,View 層展現的不是 Model 層的資料,而是 ViewModel 的資料,由 ViewModel 負責與 Model 層互動,這就完全解耦了 View 層和 Model 層,這個解耦是至關重要的,它是前後端分離方案實施的重要一環。
Vue例項的options
- el:
型別 : string | HTMLElement
作用 : 決定之後Vue例項會管理哪一個DOM。 - data:
型別 : Object | Function (元件當中data必須是一個函式)
作用 : Vue例項對應的資料物件。 - methods:
型別 : { [key: string]: Function }
作用 : 定義屬於Vue的一 些方法,可以在其他地方呼叫,也可以在指令中使用。
vue例項的生命週期
一、解析
1、什麼是生命週期:從Vue例項建立、執行、到銷燬期間,總是伴隨著各種各樣的事件,這些事件,統稱為生命週期!
2、生命週期鉤子 = 生命週期函式 = 生命週期事件
3、主要的生命週期函式分類:
- 建立期間的生命週期函式:
+ beforeCreate:例項剛在記憶體中被創建出來,此時,還沒有初始化好 data 和 methods 屬性
+ created:例項已經在記憶體中建立OK,此時 data 和 methods 已經建立OK,此時還沒有開始 編譯模板
+ beforeMount:此時已經完成了模板的編譯,但是還沒有掛載到頁面中
+ mounted:此時,已經將編譯好的模板,掛載到了頁面指定的容器中顯示
- 執行期間的生命週期函式:
+ beforeUpdate:狀態更新之前執行此函式, 此時 data 中的狀態值是最新的,但是介面上顯示的 資料還是舊的,因為此時還沒有開始重新渲染DOM節點
+ updated:例項更新完畢之後呼叫此函式,此時 data 中的狀態值 和 介面上顯示的資料,都已經完成了更新,介面已經被重新渲染好了!
- 銷燬期間的生命週期函式:
+ beforeDestroy:例項銷燬之前呼叫。在這一步,例項仍然完全可用。
+ destroyed:Vue 例項銷燬後呼叫。呼叫後,Vue 例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。
<body>
<div id="app">
<input type="button" value="修改msg" @click="msg='No'">
<h3 id="h3">{{ msg }}</h3>
</div>
<script>
// 建立 Vue 例項,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: 'ok'
},
methods: {
show() {
console.log('執行了show方法')
}
},
beforeCreate() { // 這是我們遇到的第一個生命週期函式,表示例項完全被創建出來之前,會執行它
console.log(this.msg)
this.show()
// 注意: 在 beforeCreate 生命週期函式執行的時候,data 和 methods 中的 資料都還沒有沒初始化
},
created() { // 這是遇到的第二個生命週期函式
console.log(this.msg)
this.show()
// 在 created 中,data 和 methods 都已經被初始化好了!
// 如果要呼叫 methods 中的方法,或者操作 data 中的資料,最早,只能在 created 中操作
},
beforeMount() { // 這是遇到的第3個生命週期函式,表示 模板已經在記憶體中編輯完成了,但是尚未把 模板渲染到 頁面中
console.log(document.getElementById('h3').innerText)
// 在 beforeMount 執行的時候,頁面中的元素,還沒有被真正替換過來,只是之前寫的一些模板字串
},
mounted() { // 這是遇到的第4個生命週期函式,表示,記憶體中的模板,已經真實的掛載到了頁面中,使用者已經可以看到渲染好的頁面了
console.log(document.getElementById('h3').innerText)
// 注意: mounted 是 例項建立期間的最後一個生命週期函式,當執行完 mounted 就表示,例項已經被完全建立好了,此時,如果沒有其它操作的話,這個例項,就靜靜的 躺在我們的記憶體中,一動不動
},
// 接下來的是執行中的兩個事件
beforeUpdate() { // 這時候,表示 我們的介面還沒有被更新【資料被更新了嗎? 資料肯定被更新了】
console.log('介面上元素的內容:' + document.getElementById('h3').innerText)
console.log('data 中的 msg 資料是:' + this.msg)
// 得出結論: 當執行 beforeUpdate 的時候,頁面中的顯示的資料,還是舊的,此時 data 資料是最新的,頁面尚未和 最新的資料保持同步
},
updated() {
console.log('介面上元素的內容:' + document.getElementById('h3').innerText)
console.log('data 中的 msg 資料是:' + this.msg)
// updated 事件執行的時候,頁面和 data 資料已經保持同步了,都是最新的
}
});
</script>
</body>
2、基本語法
1、插值操作
Mustache語法
<div id="app">
<h2>{{massage}}</h2>
<h2>{{massage}},洛依塵</h2>
<h2>{{firstName+lastName}}</h2>
<h2>{{firstName+' '+lastName}}</h2>
<h2>{{counter*2}}</h2>
</div>
<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
firstName:"kobe",
lastName:"bryant",
counter:200
}
})
</script>
</body>
v-once指令
該指令後面不需要跟任何表示式(比如之前的v-for後面是由跟表示式的
該指令表示元素和元件(元件後面才會學習)只渲染- 次,不會隨著資料的改變而改變
<h2 v-once>{{massage}}</h2>
v-html
該指令後面往往會跟上一個string型別
會將string的html解析出來並且進行渲染
<h2>{{url}}</h2> <!-- <a href="www.baidu.com">百度一下</a> -->
<h2 v-html="url"></h2> <!-- 百度一下 -->
v-text
都是用於將資料顯示在介面中,但是通常只接受一個string型別
<h2 v-text="massage">,洛依塵</h2> <!--你好-->
v-pre
用於跳過這個元素和它子元素的編譯過程,用於顯示原本的Mustache語法
<h2 v-pre>{{massage}}</h2> <!-- {{massage}} -->
v-cloak
在某些情況下,f防止瀏覽器可能會直接顯然出未編譯的Mustache標籤。
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<div id="app" v-cloak>
<h2>{{massage}}</h2>
<h2 v-once>{{massage}}</h2>
<h2>{{url}}</h2> <!-- <a href="www.baidu.com">百度一下</a> -->
<h2 v-html="url"></h2> <!-- 百度一下 -->
<h2 v-text="massage">,洛依塵</h2>
<!--你好-->
<h2 v-pre>{{massage}}</h2> <!-- {{massage}} -->
</div>
<body>
<script src="../js/vue.js"></script>
<script>
//在vue解析之前,div裡有一個屬性c-cloak
//在vue解析之後,div裡沒有一個屬性c-cloak
const app = new Vue({
el: "#app",
data: {
massage: "你好",
url: '<a href="www.baidu.com">百度一下</a>'
}
})
</script>
</body>
2、繫結屬性
v-bind
v-bind用於繫結一個或多個屬性值,或者向另-一個元件傳遞props值
<div id="app">
<!-- <img src="{{imgURL}}" alt=""> -->
<!-- 錯誤的用法:這裡不可以使用mustache語法-->
<!-- 正確用法:使用v-band指令 -->
<a v-bind:href="aHref">百度</a>
<img v-bind:src='imgURL' alt="" >
<!-- 語法糖的寫法 -->
<a :href="aHref">百度</a>
<img :src='imgURL' alt="" >
</div>
<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
imgURL:'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
aHref:"https://www.baidu.com/"
}
})
</script>
</body>
v-bind 動態繫結class(物件語法)
- 可以通過{ }繫結一個類
- 也可以通過判斷,傳入多個值
- 和普通類同時存在,並不衝突
- 如果過於複雜,可以放在一個methods或者computed中
<style>
.active{
color: red;
}
</style>
</head>
<div id="app">
<!-- <h2 class="active">{{massage}}</h2>
<h2 :class="active">{{massage}}</h2> -->
<!-- <h2 :class="{類名1:ture,類名2:boolean}">{{massage}}</h2> 對class物件進行選擇-->
<h2 v-bind:class="{active: isActive , line: isLine}">{{massage}}</h2>
<!-- 將內容放在一個methods裡,並呼叫 -->
<h2 v-bind:class="getClasses()">{{massage}}</h2>
<button v-on:click="bntClick">按鈕</button>
<!-- 監聽按鈕,使用bntClick方法 -->
</div>
<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
active:'active',
isActive:true, //設定boolean值決定是否啟用
isLine:true
},
methods:{
bntClick: function(){
this.isActive=!this.isActive
},
getClasses:function(){
return {active: this.isActive, line: this.isLine}
}
}
})
</script>
</body>
v-bind 動態繫結class(陣列語法)
<div id="app">
<!-- 如果在[]數組裡的元素加了引號,代表他是一個字串,而不是引用一個變數 -->
<h2 :class="[active,line]">{{massage}}</h2>
<h2 :class="['active','line']">{{massage}}</h2>
<h2 :class="getClasses()">{{massage}}</h2>
</div>
<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
active:"aaa",
line:"bbb"
},
methods:{
getClasses:function(){
return [this.active,this.line]
}
}
})
</script>
</body>
小作業:點選列表中的哪一項, 那麼該項的文字變成紅色
<style>
.active {
color: red;
}
</style>
</head>
<div id="app">
<ul>
<li v-for="(item, index) in movies" :class="{active: currentIndex === index}" @click="liClick(index)">
<!-- {active: currentIndex === index}當currentIndex === index為true時,改變顏色 -->
{{index}}.{{item}}
</li>
</ul>
</div>
<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
movies: ['海王', '火影忍者', '進擊的巨人', '死神'],
currentIndex: 0
},
methods: {
liClick(index) {
this.currentIndex = index
}
}
})
</script>
</body>
v-bind 繫結style
<div id="app"> <!-- <h2 :style="{key(屬性名):value(屬性值)}">{{massage}}</h2> --> <!-- 這裡要加' '要不然vue會去解析50px這個變數然後報錯 --> <h2 :style="{fontSize: '50px'}">{{massage}}</h2> <!-- finalSize當成一個變數在使用 --> <h2 :style="{fontSize: finalSize}">{{massage}}</h2> <!-- 也可以拼接 --> <h2 :style="{fontSize: finalSize + 'px',color:finalColor}">{{massage}}</h2> <!-- 陣列語法 --> <h2 :style="[baseStyle,baseStyle1]">{{massage}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好", finalSize: 100, finalColor: 'red', baseStyle:{color:'red'}, baseStyle1:{fontSize:'75px'} } }) </script></body>
3、計算屬性
一、什麼是計算屬性
模板內的表示式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。
二、計算屬性的用法
在一個計算屬性裡可以完成各種複雜的邏輯,包括運算、函式呼叫等,只要最終返回一個結果就可以。
<div id="app"> <h2>{{firstName+' '+lastName}}</h2> <h2>{{fullName}}</h2> <h2>總價格:{{totalPrice}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { firstName:"luo", lastName:"yichen", books:[ {id:100, name: 'java核心技術' , price:100}, {id:101, name: 'c核心技術' , price:100}, {id:102, name: 'php核心技術' , price:100}, {id:103, name: 'python核心技術' , price:100} ] }, // computed: 計算屬性() computed:{ fullName:function(){ return this.firstName+' '+this.lastName }, totalPrice:function(){ let result =0 for (let i=0;i < this.books.length; i++){ result += this.books[i].price } return result; } } }) </script>
計算屬性的getter和setter
每個計算屬性都包含一個getter和一個setter
- 在上面的例子中,我們只是使用getter來讀取。
- 在某些情況下,你也可以提供一個setter方法 (不常用)。
- 在需要寫setter的時候,程式碼如下: .
<div id="app"> <h2>{{fullName}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { firstName: "luo", lastName: "yichen", }, computed: { // fullName: function () { // return this.firstName + ' ' + this.lastName // } // 計算屬性一般沒有set值,只讀屬性。 fullName:{ set: function(newValue){ const names = newValue.split(" "); this.firstName = names[0]; this.lastName = names[1]; }, get: function(){ return this.firstName + ' ' + this.lastName } }, // 簡潔寫法 // fullName:function(){ // return this.firstName+' '+this.lastName // } } }) </script></body>
計算屬性與methods對比
<div id="app"> <!-- 通過拼接:語法過於繁瑣 --> <h2>{{firstName}} {{lastName}}</h2> <!-- 通過定義methods 每次都要呼叫--> <h2>{{getFullName()}}</h2> <!-- 通過computed 如果沒有發生改變只需要呼叫一次--> <h2>{{fullName}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { firstName: "luo", lastName: "yichen" }, methods: { getFullName: function () { return this.firstName + ' ' + this.lastName } }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) </script></body>
4、事件監聽
可以用
v-on
指令監聽 DOM 事件,並在觸發時執行一些 JavaScript 程式碼。獲取到瀏覽器引數的event物件: $event
<div id="app"> <h2>{{counter}}</h2> <button v-on:click="increment">+</button> <button v-on:click="decrement">-</button> <!-- 語法糖 當沒引數時()可以不用寫 --> <button @click="increment">+</button> <button @click="decrement">-</button> <!-- 事件呼叫時沒有引數 --> <button @click="bnt1Click()">按鈕1</button> <button @click="bnt1Click">按鈕1</button> <!-- 在事件定義前,寫函式省略了小括號,但是方法本身需要一個引數,這個時候 Vue會將瀏覽器預設生成的event事件物件作為引數傳入方法中 --> <button @click="bnt2Click(123)">按鈕2</button> <button @click="bnt2Click()">按鈕2</button> <button @click="bnt2Click">按鈕2</button> <!-- 定義方法時,我們需要event物件,同時又需要其他引數 --> <!-- 在呼叫方式時,如何手動的獲取到瀏覽器引數的event物件: $event --> <button @click="bnt3Click('abc',$event)">按鈕3</button></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { counter: 0 }, methods:{ increment(){ this.counter++ }, decrement(){ this.counter-- }, bnt1Click(){ console.log("bnt1Click"); }, bnt2Click(abc){ console.log("--------------",abc); }, bnt3Click(abc,event){ console.log("++++++++++++++", abc,event); } } }) // 如果我們函式需要引數,但是沒有傳入引數,那麼函式的形參為undefined function abc(name){ console.log(name); } abc() </script></body>
v-on的修飾符
.stop修飾符的使用
當多對標籤進行重疊的時候, 你點選最上面的一層標籤的時候, 會自動的冒泡到他下面的所有標籤上面
而.stop
就是阻止冒泡使用的.prevent修飾符的使用
在
form
表單提交時候或者在點選a
標籤的時候, 會阻止提交或跳轉.keyup監聽某個鍵盤的鍵帽
監聽某個鍵盤的鍵位
.once修飾符的使用
繫結後只會觸發一次
<div id="app"> <!-- 1. .stop --> <div @click='divClick'> aaaaa <button @click.stop='bntClick'>按鈕</button> </div> <!-- 2. .prevent --> <form action="baidu"> <input type="submit" value="提交" @click.prevent='submitClick'> </form> <!-- 3. 監聽某個鍵盤的鍵位 --> <input type="text" @keyup.enter="keyUp"> <!-- 4. once修飾符的使用 --> <button @click.once='bnt2Click'>按鈕</button></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好" }, methods: { bntClick() { console.log('bnt') }, divClick() { console.log('div') }, submitClick() { console.log("submitClick") }, keyUp() { console.log("up") }, bnt2Click() { console.log('bnt2'); } } }) </script></body>
5、條件判斷
v-if的原理:
v-if後面的條件為false時,對應的元素以及其子元素不會渲染。
也就是根本沒有不會有對應的標籤出現在DOM中。
<div id="app"> <h2 v-if="score>90">優秀</h2> <h2 v-else-if="score>80">良好</h2> <h2 v-else-if="score>60">及格</h2> <h2 v-else>不及格</h2> <h1>{{result}}</h1> <h2 v-if="isShow">{{massage}}</h2> <h1 v-else>當isShow為false時顯示我</h1></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好", isShow: true, score: 99 }, computed: { result() { let showMessage = ''; if (this.score >= 90) { showMessage = "優秀" } else if (this.score >= 80) { showMessage = "良好" } // ... return showMessage } } }) </script></body>
使用者切換的小案例
<div id="app"> <span v-if="isUser"> <label for="username">使用者賬號</label> <input type="text" id="username" placeholder="使用者賬號" key='username'> </span> <span v-else> <label for="emailname">使用者郵箱</label> <input type="text" id="emailname" placeholder="使用者郵箱" key='emailname'> </span> <button @click="isUser = !isUser">切換型別</button></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { isUser:true } }) </script></body>
小問題:
- 如果我們在有輸入內容的情況下,切換了型別,我們會發現文字依然顯示之前的輸入的內容。
- 但是按道理講,我們應該切換到另外一個input元素中了。
- 在另一個input元素中,我們並沒有輸入內容。
- 為什麼會出現這個問題呢?
問題解答:
- 這是因為Vue在進行DOM渲染時,出於效能考慮,會盡可能的複用已經存在的元素,而不是重新建立新的元素。
- 在上面的案例中, Vue內部會發現原來的input元素不再使用,直接作為else中的input來使用了.
解決方案:
- 如果我們不希望Vue出現類似重複利用的問題,可以給對應的input新增key
- 並且我們需要保證key的不同
Virtual DOM 是什麼?
Virtual DOM 其實就是一棵以 JavaScript 物件( VNode 節點)作為基礎的樹,用物件屬性來描述節點,實際上它只是一層對真實 DOM 的抽象。最終可以通過一系列操作使這棵樹對映到真實環境上。
簡單來說,可以把Virtual DOM 理解為一個簡單的JS物件,並且最少包含標籤名( tag)、屬性(attrs)和子元素物件( children)三個屬性。不同的框架對這三個屬性的命名會有點差別。
對於虛擬DOM,咱們來看一個簡單的例項,就是下圖所示的這個,詳細的闡述了模板 → 渲染函式 → 虛擬DOM樹 → 真實DOM
的一個過程
Virtual DOM 作用是什麼?
虛擬DOM的最終目標是將虛擬節點渲染到檢視上。但是如果直接使用虛擬節點覆蓋舊節點的話,會有很多不必要的DOM操作。例如,一個ul標籤下很多個li標籤,其中只有一個li有變化,這種情況下如果使用新的ul去替代舊的ul,因為這些不必要的DOM操作而造成了效能上的浪費。
為了避免不必要的DOM操作,虛擬DOM在虛擬節點對映到檢視的過程中,將虛擬節點與上一次渲染檢視所使用的舊虛擬節點(oldVnode)做對比,找出真正需要更新的節點來進行DOM操作,從而避免操作其他無需改動的DOM。
其實虛擬DOM在Vue.js主要做了兩件事:
- 提供與真實DOM節點所對應的虛擬節點vnode
- 將虛擬節點vnode和舊虛擬節點oldVnode進行對比,然後更新檢視
v-if和v-show的區別
v-show控制的是節點的display屬性 v-if是將節點刪除了 如果節點需要頻繁顯示隱藏 使用v-show效能更佳!
<div id="app"> <!-- v-if: 當條件為false時,包含v-if指令的元素,根本就不會存在dom中 --> <h2 v-if='isShow' id="aaa">{{massage}}</h2> <!-- V- show:當條件為false時,v-show只是給我們的元素新增一個行內樣式: display: none --> <h2 v-show='isShow' id="bbb">{{massage}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好", isShow: true } }) </script></body>
6、迴圈遍歷
當我們有一組資料需 要進行渲染時,我們就可以使用v-for來完成。
v-for的語法類似於JavaScript中的for迴圈。
格式如下: item in items的形式。
<div id="app"> <!-- 1.在遍歷的過程中,沒有使用索引值(下標值) --> <ul> <li v-for='item in names'>{{item}}</li> </ul> <!-- 2.在遍歷過程中,獲取索引值 --> <ul> <li v-for='(item,index) in names'> {{index+1}}.{{item}} </li> </ul> <!-- 1.在遍歷物件的過程中,如果只是獲取一個值,那麼獲取到的是value --> <ul> <li v-for="item in info">{{item}}</li> </ul> <!-- 2., 獲取key和value 格式(value,key) --> <ul> <li v-for="(value,key) in info">{{value}}-{{key}}</li> </ul> <!-- 3. 獲取key和value和index 格式(value,key,index)--> <ul> <li v-for="(value,key,index) in info">{{value}}-{{key}}-{{index}}</li> </ul></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { names: ['why', 'who', 'what', 'where'] //遍歷陣列 }, info: { //遍歷物件 name: 'lyc', age: 18, height: 1.88 } }) </script></body>
v-for加key屬性
為什麼需要這個key屬性呢(瞭解) ?
- 這個其實和Vue的虛擬DOM的Diff演算法有關係。
- 這裡我們借用React' S diff algorithm中的一張圖來簡單說明一下:
當某一層有很多相同的節點時,也就是列表節點時,我們希望插入一一個新
的節點- 我們希望可以在B和C之間加一一個F , Diff演算法預設執行起來是這樣的。
- 即把C更新成F , D更新成C , E更新成D ,最後再插入E ,是不是很沒有
效率?
所以我們需要使用key來給每個節點做一個唯一標識
Diff演算法就可以正確的識別此節點
0找到正確的位置區插入新的節點。
所以一句話, key的作用主要是為了高效的更新虛擬DOM。
哪些陣列方法是響應式的
<body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { letters: ['A', 'C', 'B', 'D', 'E'] }, methods: { btnClick() { // 1.push() 在陣列最後新增元素 this.letters.push('aaa','bbb') // 2.pop() 在陣列最後刪除一個元素 this.letters.pop(); // 3.shift() 刪除在陣列第一個元素 this.letters.shift(); // 4.unshift() 在陣列最前面新增元素 this.letters.unshift('ddd','ddd'); // 5.splice() 刪除/插入/替換元素 // 刪除元素: 第一引數傳入你從第幾個元素開始刪除,第二引數傳入你要刪除的幾個元素(如果沒有傳,就刪除後面所有元素) // 插入元素: 第二個傳入0,後面跟上要新增的值 // 替換元素: 第二引數傳入你要刪除元素,後面追加你要寫入的元素完成替換 this.letters.splice(1,3,'m','n','l') // 6.sort() 排序 this.letters.sort() // 7.reverse() 反轉 this.letters.reverse() // 注意:通過索引值直接來修改陣列中的元素 不是響應式 // this.letters[0]='bbbbbbbbbbbb' // set(要修改的物件,索引值,修改後的值) Vue.set(this.letters,0,'bbbbbb') } } }) // 擴充套件知識:可變引數 // function sum(...sum){ // console.log(sum); // } // sum(11,223,44,56,77,889,9,1) </script></body>
6、表單繫結
- 表單控制元件在實際開發中是非常常見的。特別是對於使用者資訊的提交,需要大量的表單。
- Vue中使用v-model指令來實現表單元素和資料的雙向繫結。
<body> <div id="app"> <input type="text" v-model="massage"> {{massage}} </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好" } }) </script></body>
- 當我們在輸入框輸入內容時
- 因為input中的v-model綁定了message ,所以會實時將輸入的內容傳遞給message , message發生改變。
- 當message發生改變時,因為上面我們使用Mustache語法,將message的值插入到DOM中,所以DOM會發生響應的改變。
- 所以,通過v-model實現了雙向的繫結。
原理:
<div id="app"> <!-- <input type="text" v-model="massage"> --> <!-- <input type="text" :value="massage" @input="valueChange"> --> <input type="text" :value="massage" @input="massage = $event.target.value"> {{massage}} </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { massage: "你好" }, methods: { valueChange(event) { this.massage = event.target.value; } } }) </script></body>
v-model結合radio型別
<div id="app"> <label for=""> <input type="radio" id="male" value="男" v-model="sex">男 </label> <label for=""> <input type="radio" id="female" value="女" v-model="sex">女 </label> <h2>{{sex}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "你好", sex:'男' } }) </script></body>
v-model結合checkbox型別
單個勾選框: .
- v-modelI即為布林值。
- 此時input的value並不影響v-model的值。
多個複選框:
- 多個複選框時,因為可以選中多個,所以對應的data中屬性是一個數組。
- 當選中某一個時 ,就會將input的value新增到陣列中。
<div id="app"> <!-- 單選框 --> <!-- <label for="agree"> <input type="checkbox" id="agree" v-model="isAgree">同意協議 </label> <h2>{{isAgree}}</h2> <button :disabled="!isAgree">下一步</button> --> <!-- 多選框 --> <!-- <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> --> <label v-for="item in originHobbies" :for="item"> <input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}} </label> </div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "你好", isAgree: false,//單選框 hobbies:[],//多選框 originHobbies:['籃球','足球','乒乓球','檯球','高爾夫球'] //也可以通過值繫結來從伺服器獲取值 } }) </script></body>
v-model結合select
單選:只能選中一個值。
- v-model繫結的是一個值。
- 當我們選中option中的一個時,會將它對應的value賦值到mySelect中
多選:可以選中多個值。
- v-model繫結的是一個數組。
- 當選中多個值時,就會將選中的option對應的value新增到陣列mySelects中
<body> <div id="app"> <!-- 1、選擇一個 --> <select name="abc" id="" v-model="fruit"> <option value="蘋果">蘋果</option> <option value="香蕉">香蕉</option> <option value="榴蓮">榴蓮</option> <option value="西瓜">西瓜</option> </select> <h2>{{fruit}}</h2> <!-- 2、選擇多個 --> <select name="abc" id="" v-model="fruits" multiple> <option value="蘋果">蘋果</option> <option value="香蕉">香蕉</option> <option value="榴蓮">榴蓮</option> <option value="西瓜">西瓜</option> </select> <h2>{{fruits}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "你好", fruit:"香蕉", fruits:[] } }) </script></body>
v-model的修飾符
lazy修飾符:
- 預設情況下, v- model預設是在input事件中同步輸入框的資料的。
- 也就是說, 一旦有資料發生改變對應的data中的資料就會自動發生
改變。 - lazy修飾符可以讓資料在失去焦點或者回車時才會更新:
number修飾符:
- 預設情況下,在輸入框中無論我們輸入的是字母還是數字,都會被
當做字串型別進行處理。 - 但是如果我們希望處理的是數字型別,那麼最好直接將內容當做數
字處理。 - number修飾符可以讓在輸入框中輸入的內容自動轉成數字型別:
trim修飾符:
- 如果輸入的內容首尾有很多空格,通常我們希望將其去除
- trim修飾符可以過濾內容左右兩邊的空格
<div id="app"> <!-- 1.修飾符:lazy --> <input type="text" v-model.lazy="message"> <h2>{{message}}</h2> <!-- 2.修飾符:number --> <input type="number" v-model.number="age"> <h2>{{typeof age}}</h2> <!-- 3.修飾符:trim --> <input type="text" v-model.trim="name"> <h2>{{name}}</h2></div><body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "你好", age:12, name:'' } }) </script></body>
綜合-書籍購物車案例
- HTML
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="./style.css"></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>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td>{{item.price | showPrice}}</td> <td> <button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button> {{item.count}} <button @click="increment(index)">+</button> </td> <td><button @click="removeHandler(index)">移除</button></td> </tr> </tbody> </table> <h2> 總價格: {{totalPrice | showPrice}} </h2> </div> <div v-else> <h1>購物車為空</h1> </div> </div> <script src="../js/vue.js"></script> <script src="./main.js"></script></body></html>
- CSS
table{ border: 1px solid #000; border-collapse: collapse; border-spacing: 0;}th,td{ padding: 8px 16px; border: 1px solid #000; text-align: left;}th{ background-color: #f7f7f7; color: #5c6b77; font-weight: 600;}
- JS
const app = new Vue({ el: "#app", data: { books: [{ id: 1, name: '《演算法導論》', date: "2006-9", price: 85.00, count: 1 }, { id: 2, name: '《演算法導論》', date: "2006-9", price: 85.00, count: 1 }, { id: 3, name: '《演算法導論》', date: "2006-9", price: 85.00, count: 1 }, { id: 4, name: '《演算法導論》', date: "2006-9", price: 85.00, count: 1 } ] }, methods: { // getFinalPrice(price){ // return '¥'+price.toFixed(2) //toFixed(2)保留兩位小數 // } increment(index) { this.books[index].count++ }, decrement(index) { this.books[index].count-- }, removeHandler(index) { this.books.splice(index, 1) } }, filters: { //過濾器 showPrice(price) { return '¥' + price.toFixed(2) } }, computed: { totalPrice() { let totalPrice = 0; for (let i = 0; i < this.books.length; i++) { totalPrice += this.books[i].price * this.books[i].count; } return totalPrice; } }})
JS高階函式
程式設計正規化:指令式程式設計/宣告式程式設計
程式設計正規化:面向物件程式設計(第一公民:物件)/函數語言程式設計(第一公民:函式)
filter/map/reduce
filter中的回撥函式有一個要求:必須返回一個 boolean值
true:當返回true時,函式內部會自動將這次回撥的n加入到新的陣列中
false:當返回false時,函式內部會過濾掉這次的n
- 基本寫法
const nums = [10,20,111,222,444,40,50]// 1.需求:取出小於100的數字let newNums = []for(let n of nums){ if(n > 100){ newNums.push(n) }}// 2.需求:將所有小於160的數字進行轉化:全部*2let new2Nums = []for(let n of newNums){ new2Nums.push(n*2)}// 3.需求:將所有new2Nums數字相加,得到最終的記過let total = 0for(let n of new2Nums){ total +=n}console.log(total)
- 高階寫法
const nums = [10,20,111,222,444,40,50]// 1.filter函式的使用let newNums = nums.filter(function(n){ return n<100})console.log(newNums)// 2.map函式的使用let new2Nums = newNums.map(function(n){ return n*2})console.log(new2Nums)// 3.reduce函式的使用// reduce作用對陣列中所有的內容進行彙總let total = new2Nums.reduce(function(preValue,n){ return preValue + n;},0)console.log(total)// 第一次: revalue 0 n 20// 第二次: revalue 20 n 40// 第二次: revalue 60 n 80// 第二次: revalue 140 n 100// 240
- 高階綜合寫法
const nums = [10,20,111,222,444,40,50]// 綜合let total = nums.filter(function(n){ return n<100}).map(function(n){ return n*2}).reduce(function(preValue,n){ return preValue + n;},0) //初始化console.log(total)//使用箭頭函式進一步簡化let total = nums.filter(n => n<100).map(n => n*2).reduce((pre,n) => pre+n)console.log(total)
3、元件化開發
一、什麼是元件化開發
人面對複雜問題的處理方式:
任何一個人處理資訊的邏輯能力都是有限的
所以,當面對一個非常複雜的問題時,我們不太可能一次性搞定一大堆的內容。
但是,我們人有一種天生的能力,就是將問題進行拆解。
如果將一個複雜的問題,拆分成很多個可以處理的小問題,再將其放在整體當中,你會發現大的問題也會迎刃而解。
元件化也是類似的思想:
如果我們將一個頁面中所有的處理邏輯全部放在一起,處理起來就會變得非常複雜,而且不利於後續的管理以及擴充套件。
但如果,我們講一個頁面拆分成一個個小的功能塊,每個功能塊完成屬於自己這部分獨立的功能,那麼之後整個頁面的管理和維護就變得非常容易了。
我們將一個完整的頁面分成很多個元件。
每個元件都用於實現頁面的一個功能塊。
而每一個元件又可以進行細分。
二、Vue元件化思想
元件化是Vue.js中的重要思想
它提供了一種抽象,讓我們可以開發出一個個獨立可複用的小元件來構造我們的應用。
任何的應用都會被抽象成一顆元件樹。
元件化思想的應用:
有了元件化的思想,我們在之後的開發中就要充分的利用它。
儘可能的將頁面拆分成一個個小的、可複用的元件。
這樣讓我們的程式碼更加方便組織和管理,並且擴充套件性也更強。
所以,元件是Vue開發中,非常重要的一個篇章,要認真學習。
三、註冊元件的基本步驟
元件的使用分成三個步驟:
建立元件構造器
註冊元件
使用元件。
我們來看看通過程式碼如何註冊元件
檢視執行結果:
和直接使用一個div看起來並沒有什麼區別。
但是我們可以設想,如果很多地方都要顯示這樣的資訊,我們是不是就可以直接使用來完成呢?
四、註冊元件步驟解析
這裡的步驟都代表什麼含義呢?
1.Vue.extend():
呼叫Vue.extend()建立的是一個元件構造器。
通常在建立元件構造器時,傳入template代表我們自定義元件的模板。
該模板就是在使用到元件的地方,要顯示的HTML程式碼。
事實上,這種寫法在Vue2.x的文件中幾乎已經看不到了,它會直接使用下面我們會講到的語法糖,但是在很多資料還是會提到這種方式,而且這種方式是學習後面方式的基礎。
2.Vue.component():
呼叫Vue.component()是將剛才的元件構造器註冊為一個元件,並且給它起一個元件的標籤名稱。
所以需要傳遞兩個引數:1、註冊元件的標籤名 2、元件構造器
3.元件必須掛載在某個Vue例項下,否則它不會生效。
我們來看下面我使用了三次
而第三次其實並沒有生效:
第三步的解析
<div id="app"> <my-cpn></my-cpn></div><body> <script src="../js/vue.js"></script> <script> //1.建立元件構造器物件 const cpnC = Vue.extend({ template: ` <div> <h2>我是標題</h2> <p>我是內容,紅紅火火恍恍惚惚</p> <p>我是內容,紅紅火火恍恍惚惚</p> </div>` }) // 2.註冊元件 Vue.component('my-cpn',cpnC) const app = new Vue({ el: "#app", data: { message: "你好" } }) </script></body>
五、全域性元件和區域性元件
當我們通過呼叫Vue.component()註冊元件時,元件的註冊是全域性的
這意味著該元件可以在任意Vue示例下使用。
如果我們註冊的元件是掛載在某個例項中, 那麼就是一個區域性元件
<div id="app"> <cpn></cpn></div><div id="app2"> <cpn></cpn></div><body> <script src="../js/vue.js"></script> <script> //1.建立元件構造器物件 const cpnC = Vue.extend({ template: ` <div> <h2>我是標題</h2> <p>我是內容,紅紅火火恍恍惚惚</p> <p>我是內容,紅紅火火恍恍惚惚</p> </div>` }) // 2.註冊元件(全域性元件,意味著可以在多個Vue的實力下面使用) Vue.component('my-cpn',cpnC) const app = new Vue({ el: "#app", data: { message: "你好" }, //在Vue例項內註冊元件就是區域性元件 components:{ //cpn使用元件時的標籤名 cpn:cpnC } }) const app2 = new Vue({ el: "#app2", data: { message: "你好" } }) </script></body>
六、父子元件
父子元件錯誤用法:以子標籤的形式在Vue例項中使用
- 因為當子元件註冊到父元件的components時, Vue會編譯好父元件的模組
- 該模板的內容已經決定了父元件將要渲染的HTML (相當於父元件中已經有了子元件中的內容了)
- 是隻能在父元件中被識別的。
- 類似這種用法, 是會被瀏覽器忽略的。
<div id="app"> <cpn1></cpn1> <cpn2></cpn2></div><body> <script src="../js/vue.js"></script> <script> // 1.建立第一個元件構造器(子元件) const cpnC1 = Vue.extend({ template:` <div> <h2>我是標題</h2> <p>我是內容,紅紅火火恍恍惚惚</p> </div> ` }) // 2.建立第二個元件構造器(父元件) const cpnC2 = Vue.extend({ template:` <div> <h2>我是標題</h2> <p>我是內容,呵呵呵呵呵呵呵呵</p> <cpn1></cpn1> </div> `, components:{ //在父元件中註冊子元件 cpn1:cpnC1 } }) // 可以把Vue當成一個root元件 const app = new Vue({ el: "#app", data: { massage: "你好" }, components:{ cpn2:cpnC2 } }) </script></body>
七、元件註冊語法糖
在上面註冊元件的方式,可能會有些繁瑣。
- Vue為了簡化這個過程,提供了註冊的語法糖。
- 主要是省去了呼叫Vue.extend()的步驟,而是可以直接使用一個物件來代替。
語法糖註冊全域性元件和區域性元件:
<div id="app"> <cpn1></cpn1> <cpn2></cpn2></div><body> <script src="../js/vue.js"></script> <script> // 1.全域性元件註冊的語法糖 // 1.建立元件構造器 // const cpn1 = Vue.extend({ // template:` // <div> // <h2>我是標題</h2> // <p>我是內容,紅紅火火恍恍惚惚</p> // </div> // ` // }) // 2.註冊元件 Vue.component('cpn1', { template: ` <div> <h2>我是標題</h2> <p>我是內容,紅紅火火恍恍惚惚</p> </div> ` }) // 註冊區域性元件的語法糖 const app = new Vue({ el: "#app", data: { massage: "你好" }, components: { 'cpn2': { template: ` <div> <h2>我是標題</h2> <p>我是內容,呵呵呵呵呵呵呵</p> </div> ` } } }) </script></body>
八、模板的分離寫法
剛才,我們通過語法糖簡化了Vue元件的註冊過程,另外還有一個地方的寫法比較麻煩,就是template模組寫法。
如果我們能將其中的HTML分離出來寫,然後掛載到對應的元件上,必然結構會變得非常清晰。
Vue提供了兩種方案來定義HTML模組內容:
- 使用