Vue3 基礎
概述
Vue (發音為 /vjuː/,類似 view) 是一款用于建構使用者界面的 JavaScript 架構。它基于标準 HTML、CSS 和 JavaScript 建構,并提供了一套聲明式的、元件化的程式設計模型,幫助你高效地開發使用者界面。無論是簡單還是複雜的界面,Vue 都可以勝任。
Vue 的兩個核心功能:
- 聲明式渲染:Vue 基于标準 HTML 拓展了一套模闆文法,使得我們可以聲明式地描述最終輸出的 HTML 和 JavaScript 狀态之間的關系。
- 響應性:Vue 會自動跟蹤 JavaScript 狀态并在其發生變化時響應式地更新 DOM。
Vue3官方文檔
Vite官方文檔
安裝Vue
一、使用CDN
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
二、npm安裝
npm init [email protected]
三、下載下傳JavaScript檔案自行托管
使用JS的方式引入Vue
<!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>vue3簡單使用</title>
<script src="./vue3.js"></script>
</head>
<body>
<div id="counter">
<p>{{uname}}</p>
<p>{{age}}</p>
</div>
<script>
// 配置對象
const counter = {
data: function () {
return {
uname: "小明",
age: 0
}
}
};
// 使用createApp函數建立一個應用執行個體
// 傳入配置對象
let app = Vue.createApp(counter)
// 應用執行個體必須調用mount函數,挂載後才會渲染出來
.mount("#counter");
//資料雙向綁定
app.age = 18;
</script>
</body>
</html>
使用vite
簡介
Vite是要給web開發建構工具,由于其原生ES子產品導入方式,可以實作閃電般的冷伺服器啟動。
使用vite搭建項目
npm create [email protected]
或者:
npm create [email protected] my-vue-app -- --template vue
接着依次執行指令啟動vue項目:
cd my-vue-app
npm install
npm run dev
模闆文法
Vue 使用一種基于 HTML 的模闆文法,使我們能夠聲明式地将其元件執行個體的資料綁定到呈現的 DOM 上。所有的 Vue 模闆都是文法層面合法的 HTML,可以被符合規範的浏覽器和 HTML 解析器解析。
在底層機制中,Vue 會将模闆編譯成高度優化的 JavaScript 代碼。結合響應式系統,當應用狀态變更時,Vue 能夠智能地推導出需要重新渲染的元件的最少數量,并應用最少的 DOM 操作。
基本使用
<script>
export default {
data() {
return {
name: "小明123",
age: 18,
num: 0,
rawHtml: "<h2 style='color:red;'>hello msg</h2>",
myid: "id01",
isBtnDisabled: true,
objAttrs: {
id: "id01",
class: "box"
},
imgUrl: "https://cn.vitejs.dev/logo-with-shadow.png",
attributeName: "id",
mouseEvent: "click",
}
},
methods: {
changeNum() {
this.num++;
},
changeColor() {
this.id = "id01";
},
alertMsg() {
alert("hello world");
}
}
}
</script>
<template>
<!-- 文本插值 -->
<p>姓名:{{ name }}</p>
<p>年齡:{{ age }}</p>
<p>數量:{{ num }}</p>
<!-- 僅修改一次 -->
<p v-once>數量:{{ num }}</p>
<button @click="changeNum">修改num</button>
<!-- 使用html -->
<p v-html="rawHtml"></p>
<!-- 屬性綁定 -->
<p v-bind:id="myid">v-bind</p>
<!-- v-bind簡寫 -->
<p :id="myid">v-bind2</p>
<!-- 布爾類型 -->
<button :disabled="isBtnDisabled">v-bind2</button><br>
<!-- 綁定多個屬性 -->
<p v-bind="objAttrs">hello world</p>
<!-- 動态參數 -->
<p v-bind:[attributeName]="myid">動态屬性1</p>
<img v-bind:src="imgUrl" style="width: 50px;">
<!-- 簡寫 -->
<p :[attributeName]="myid">動态屬性2</p>
<button @[mouseEvent]="attributeName = 'class'">動态事件</button>
<button @click="mouseEvent = 'mouseover'">改變事件</button><br>
<!-- 點選事件 -->
<button v-on:click="changeColor">修改顔色</button>
<!-- 簡寫 -->
<button @click="changeColor">修改顔色</button><br>
<!-- 使用JavaScript表達式 -->
<p>{{ num + 1 }}</p>
<p>{{ name.split("").reverse().join("") }}</p>
</template>
<style>
#id01 {
color: red;
}
#id02 {
color: blue;
}
.id01 {
color: green;
}
.id02 {
color: yellowgreen;
}
.active {
color: red;
}
.box {
border: 1px dashed red;
}
</style>
條件渲染
<script>
export default {
data() {
return {
age: 68,
isShow: true
}
}
}
</script>
<template>
<!-- v-if條件渲染 -->
<p v-if="age < 18">未成年人</p>
<p v-if="age >= 18 && age < 60">年輕人</p>
<p v-else>老人</p>
<!-- v-show,本質是display:none; -->
<p v-show="isShow">
hello template
</p>
</template>
-
:會根據條件進行渲染,切換時元素會被銷毀或重建,是以切換開銷大。v-if
-
:本質是通過v-for
進行顯示和隐藏。display
清單渲染
<script>
export default {
data() {
return {
userList: [
{ name: "張三", age: 19, address: "北京" },
{ name: "李四", age: 29, address: "上海" },
{ name: "王五", age: 39, address: "廣州" }
],
userInfo: {
name: "小白",
title: "頂級作者",
bookName: "西遊記"
}
}
}
}
</script>
<template>
<!-- v-for周遊數組 -->
<ul>
<li v-for="(item, index) in userList">
編号:{{ index }} 姓名:{{ item.name }} 年齡:{{ item.age }} 位址:{{ item.address }}
</li>
</ul>
<ul>
<li v-for="({ name, age, address }, index) in userList">
編号:{{ index }} 姓名:{{ name }} 年齡:{{ age }} 位址:{{ address }}
</li>
</ul>
<!-- v-for周遊對象 -->
<ul>
<li v-for="(value, key) in userInfo">
{{ key }} : {{ value }}
</li>
</ul>
</template>
通過key管理狀态
Vue 預設按照“就地更新”的政策來更新通過
v-for
渲染的元素清單。當資料項的順序改變時,Vue 不會随之移動 DOM 元素的順序,而是就地更新每個元素,確定它們在原本指定的索引位置上渲染。
預設模式是高效的,但隻适用于清單渲染輸出的結果不依賴子元件狀态或者臨時 DOM 狀态 (例如表單輸入值) 的情況。
為了給 Vue 一個提示,以便它可以跟蹤每個節點的辨別,進而重用和重新排序現有的元素,你需要為每個元素對應的塊提供一個唯一的
key
attribute:
<script>
export default {
data() {
return {
userList: [
{ name: "張三", age: 19, address: "北京" },
{ name: "李四", age: 29, address: "上海" },
{ name: "王五", age: 39, address: "廣州" }
]
}
},
methods: {
addUser() {
this.userList.unshift({ name: "小白", age: "8", address: "成都" })
}
}
}
</script>
<template>
<!-- :key的使用 -->
<ul>
<li v-for="item in userList" :key="item">
<input type="checkbox">{{ item.name }}
</li>
</ul>
<button @click="addUser">添加user</button>
</template>
數組變化偵測
Vue 能夠偵聽響應式數組的變更方法,并在它們被調用時觸發相關的更新。這些變更方法包括:
-
push()
-
pop()
-
shift()
-
unshift()
-
splice()
-
sort()
-
reverse()
計算屬性
計算屬性隻會在依賴值發生變化時才會重新計算。
<script >
export default {
data() {
return {
message: "hello world",
firstMsg: "abc",
lastMsg: "efg"
}
},
//方法
methods: {
reverseMsg2() {
console.log("reverseMsg2");
return this.message.split("").reverse().join("");
}
},
//計算屬性
computed: {
reverseMsg() {
console.log("reverseMsg");
return this.message.split("").reverse().join("");
},
// 可寫計算屬性
fullName: {
// getter
get() {
return this.firstMsg + "-" + this.lastMsg;
},
// setter
set(newValue) {
[this.firstMsg, this.lastMsg] = newValue.split(" ");
}
}
}
}
</script>
<template>
<p>{{ message }}</p>
<p>{{ reverseMsg2() }}</p>
<p>{{ reverseMsg2() }}</p>
<p>{{ reverseMsg }}</p>
<p>{{ reverseMsg }}</p>
<button @click="message = '你好'">修改message</button>
<p>{{ fullName }}</p>
<p>{{ fullName="ABC EFG" }}</p>
</template>
說明:
列印了2次“reverseMsg2”,說明每次調用方法都會執行一次;列印了1次“reverseMsg”,說明計算屬性會緩存。
點選按鈕修改了message屬性,會重複上面操作,說明計算屬性隻有依賴值發生變化時才會重新計算。
偵聽器
監聽狀态變化。
<script >
export default {
data() {
return {
message: "hello world",
isHidden: true,
user: {
name: "小明",
age: 18,
sex: true
}
}
},
// 偵聽器
watch: {
// 偵聽器,方式一,message發生變化時調用
// message(newValue, oldValue) {
// console.log("新值:" + newValue, "舊值:" + oldValue);
// if (newValue.length < 5 || newValue.length > 10) {
// this.isHidden = false;
// } else {
// this.isHidden = true;
// }
// }
// 偵聽器,方式二,初始化時觸發
message: {
immediate: true, // 是否初始化時調用
handler(newValue, oldValue) {
if (newValue.length < 5 || newValue.length > 10) {
this.isHidden = false;
} else {
this.isHidden = true;
}
}
},
// 深度監聽,方式一,監聽對象的每個屬性
// user: {
// handler(newValue) {
// console.log(newValue);
// console.log(newValue.name);
// },
// deep: true // 是否深度監聽,給對象的每個屬性都加上偵聽器
// },
// 深度監聽,方式二,監聽對象的單個屬性
"user.name": {
handler(newValue) {
console.log(newValue);
},
deep: true // 是否深度監聽
}
}
}
</script>
<template>
<p>{{ message }}</p>
<button @click="message = '你好'">修改message</button><br>
<input type="text" v-model="message"><br>
<p :hidden="isHidden">輸入框中的内容不能小于5或大于10</p>
<button @click="user.name = '小白'">修改user.name</button>
</template>
v-bind 屬性綁定
-
可簡寫為v-bind:
,如:
簡寫為v-bind:class
。:class
<script >
export default {
data() {
return {
message: "hello wold",
//class
isActive: true,
isBgColor: true,
classObj: {
active: true,
bgColor: true
},
error: null,
activeClass: "active",
bgColorClass: "bgColor",
//style
activeColor: "red",
bgColor: "grey",
fontSize: "30px",
styleObj: {
color: "red",
'background-color': "grey",
fontSize: "30px"
}
}
},
// 計算屬性
computed: {
classObject() {
return {
active: this.isActive && !this.error,
bgColor: this.isBgColor && !this.error
}
}
}
}
</script>
<template>
<!-- 使用class -->
<p class="active">hello world1</p>
<!-- 綁定對象 -->
<p :class="{ active: isActive }">hello world2</p>
<p :class="{ active: isActive, bgColor: isBgColor }">hello world3</p>
<!-- 綁定對象簡寫 -->
<p :class="classObj">hello world4</p>
<!-- 計算屬性 -->
<p :class="classObject">hello world5</p>
<!-- 綁定數組 -->
<p :class="[activeClass, bgColorClass]">hello world6</p>
<button @click="isActive = !isActive">修改active</button>
<button @click="isBgColor = !isBgColor">修改bgColor</button>
<!-- 使用内聯樣式 -->
<p style="color:red;">hello1</p>
<!-- 綁定對象 -->
<p :style="{ color: activeColor, 'background-color': bgColor, fontSize: fontSize }">hello2</p>
<!-- 綁定對象 -->
<p :style="styleObj">hello3</p>
<!-- 綁定數組 -->
<p :style="[styleObj]">hello4</p>
</template>
<style>
.active {
color: red;
}
.bgColor {
background-color: grey;
}
</style>
v-on 事件綁定
-
可以簡寫為v-on
,如@
簡寫為v-on:click
。@click
<script >
export default {
data() {
return {
num: 0,
score: 0
}
},
methods: {
add(event) {
this.num++;
},
add2(n) {
this.num += n;
},
add3(event, n) {
this.num += n;
console.log(event);
},
addScore() {
this.score++;
},
fatherClick() {
console.log("父元素點選");
},
childClick() {
console.log("子元素點選");
},
mclick() {
console.log("送出成功");
},
onceClick() {
console.log("aaa");
},
keyupFn(e) {
console.log("按鍵修飾符:", e.key);
},
keyupEnterFn(e) {
console.log("enter");
},
keyupDirectionFn(e) {
console.log("監聽方向鍵:", e.key);
},
rightClickFn() {
console.log("滑鼠左鍵");
},
ctrlFn() {
console.log("ctrlFn");
}
}
}
</script>
<template>
<!-- 點選事件: -->
<!-- 綁定事件,直接通過js代碼處理 -->
<button @click="num++">{{ num }}</button><br>
<!-- 綁定事件,沒有傳參 -->
<button @click="add">{{ num }}</button><br>
<!-- 綁定事件,傳遞參數 -->
<button @click="add2(5)">{{ num }}</button><br>
<!-- 綁定事件,擷取傳參和事件對象 -->
<button @click="add3($event, 5)">{{ num }}</button><br>
<!-- 綁定多個處理函數 -->
<button @click="add(), addScore()">{{ num }} --- {{ score }}</button>
<!-- 事件修飾符: -->
<!-- 阻止事件冒泡 -->
<div @click="fatherClick">
<button @click.stop="childClick">阻止事件冒泡</button>
</div>
<!-- 阻止預設送出 -->
<form action="">
<input type="submit" value="阻止預設送出" @click.prevent="mclick">
</form>
<!-- 隻會觸發一次 -->
<button @click.once="onceClick">隻觸發一次</button><br>
<!-- 按鍵修飾符: -->
<input type="text" placeholder="按鍵修飾符" @keyup="keyupFn"><br>
<!-- 按鍵别名 -->
<!-- 監聽按鍵輸入 -->
<input type="text" placeholder="enter别名" @keyup.enter="keyupEnterFn"><br>
<!-- 監聽方向鍵 -->
<input type="text" placeholder="監聽方向鍵" @keyup.left.right.down.up="keyupDirectionFn"><br>
<!-- 系統按鍵, -->
<input placeholder="ctrl" @keyup.ctrl="ctrlFn" /><br>
<!-- 滑鼠按鍵:該按鍵必須在事件發出時處于按下狀态。 -->
<button @click.right="rightClickFn">滑鼠按鍵</button>
</template>
v-model 雙向綁定
v-model
可以在元件上使用以實作雙向綁定。
<script >
export default {
data() {
return {
msg: "hello world",
checked: true,
fruits: [],
sex: "男",
city: "上海",
citys: [],
desc: "abc",
num: 0,
inputMsg: ""
}
},
methods: {
changeMsg(e) {
this.msg = e.target.value;
},
changeInput(e) {
console.log(this.inputMsg);
}
}
}
</script>
<template>
<!-- v-model雙向綁定 -->
<input type="text" v-model="msg">
<h3>{{ msg }}</h3>
<!-- v-model原理: -->
<input type="text" :value="msg" @input="changeMsg"><br>
<!-- 單個多選框 -->
<input type="checkbox" v-model="checked">
<p>{{ checked }}</p>
<!-- 多選框 -->
<label><input type="checkbox" v-model="fruits" value="蘋果">蘋果</label>
<label><input type="checkbox" v-model="fruits" value="梨子">梨子</label>
<label><input type="checkbox" v-model="fruits" value="香蕉">香蕉</label>
<label><input type="checkbox" v-model="fruits" value="西瓜">西瓜</label>
<p>你喜歡的水果:{{ fruits }}</p>
<!-- 單選框 -->
<input type="radio" v-model="sex" value="男">男
<input type="radio" v-model="sex" value="女">女
<p>你的性别:{{ sex }}</p>
<!-- 單選選項框 -->
<select v-model="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="廣州">廣州</option>
</select>
<p>你選的城市:{{ city }}</p>
<!-- 多選框 -->
<select v-model="citys" multiple>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="廣州">廣州</option>
</select>
<p>你喜歡城市:{{ citys }}</p>
<!-- v-model修飾符: -->
<!-- .lazy 當輸入框失去焦點時執行 -->
<input type="text" v-model.lazy="desc">
<p>{{ desc }}</p>
<!-- .number 将輸入框的内容轉為number類型 -->
<input type="text" v-model.number="num">
<p>{{ num }} 類型:{{ typeof num }}</p>
<!-- .trim 清楚前後空格 -->
<input type="text" v-model.trim="inputMsg" @input="changeInput">
</template>