涉及的技術棧 vue3 vite bootstrap5 背景 在用bootstrap5的時候遇到一個問題,就是offcanvas在nav上的時候居然會有兩個背景BackDrop,關閉之後頁面上還有一個backdrop留在那 bootstrap5文檔裡面提供了幾個Method可以控制Offcanvas ...
Vue從0基礎到大神學習完整教程完整教程(附代碼資料)主要內容講述:vue基本概念,vue-cli的使用,vue的插值表達式,{{ gaga }},{{ if (obj.age > 18 ) { } }},vue指令,綜合案例 - 文章標題編輯vue介紹,開發vue的方式,基本使用,如何覆蓋webpack配置,目錄分析與清理,vue單文件組件的說明,vue通過data提供數據,通過插值表達式顯示數據,安裝vue開發者工具,v-bind指令,v-on指令,v-if 和 v-show,v-model,v-text 和 v-html。day-08vuex介紹,語法,模塊化,小結。面經PC端-element (上)初始化,request,router,login模塊,layout模塊,dashboard模塊(瞭解)。面經PC端 - Element (下)Article / list 列表,Article / add 添加,Article / del 刪除,Article / upd 修改,Article / preview 預覽,yarn-補充。vue指令(下),成績案例,計算屬性,屬性監聽v-for,樣式處理,基本結構與樣式,基本渲染,刪除,新增,處理日期格式,基本使用,計算屬性的緩存的問題,成績案例-計算屬性處理總分 和 平均分,計算屬性的完整寫法,大小選,基本使用,複雜類型的監聽-監聽的完整寫法,成績案例-監聽數據進行緩存,配置步驟 (兩步),使用演示。vue指令(下),成績案例,計算屬性,屬性監聽v-for,樣式處理,基本結構與樣式,基本渲染,刪除,新增,處理日期格式,基本使用,計算屬性的緩存的問題,成績案例-計算屬性處理總分 和 平均分,計算屬性的完整寫法,大小選,基本使用,複雜類型的監聽-監聽的完整寫法,成績案例-監聽數據進行緩存,配置步驟 (兩步),使用演示。組件化開發,組件通信,todo案例,作業什麼是組件化開發,組件的註冊,全局註冊組件,組件的樣式衝突 ,組件通信 - 父傳子 props 傳值,v-for 遍歷展示組件練習,單向數據流,組件通信 - 子傳父,props 校驗,佈局,任務組件todo,列表,刪除,修改:不做了!下麵代碼其實就是我想讓大家練習,添加,剩餘數量,清空已完成,小選與大選,篩選:作業,本地存儲,附加練習_1.喜歡小狗狗嗎,附加練習_2.點擊文字變色,附加練習_3. 迴圈展示狗狗,附加練習_4.選擇喜歡的狗。v-model,ref 和 $refs,$nextTick,dynamic 動態組件,自定義指令,插槽,案例:商品列表v-model 語法糖,v-model給組件使用,動態組件的基本使用,自定義指令說明,自定義指令 - 局部註冊,自定義指令 - 全局註冊,自定義指令 - 指令的值,預設插槽 slot,後備內容 (預設值),具名插槽,作用域插槽,案例概覽,靜態結構,MyTag 組件,MyTable 組件。生命周期,單頁應用程式與路由,vue-router研究生命周期的意義,生命周期函數(鉤子函數),組件生命周期分類,SPA - 單頁應用程式,路由介紹,vue-router介紹,vue-router使用,配置路由規則,路由的封裝,vue路由 - 聲明式(a標簽轉跳)導航,vue路由 - 重定向和模式,vue路由 - 編程式(JS代碼進行轉跳)導航,綜合練習 - 面經基礎版,組件緩存 keep-alive。面經 H5 端 - Vant(上)初始化,vant,axios封裝,router,主題定製-瞭解,登錄&註冊。面經 H5 端 - Vant(下)列表,詳情,收藏 與 喜歡,我的(個人中心)。Day01_vuex今日學習目標(邊講邊練),1.vuex介紹,2.vuex學習內容,3.vuex例子準備,vuex-store準備,5.vuex-state數據源,【vuex-mutations定義-同步修改,【vuex-mutations使用,8.vuex-actions定義-非同步修改,9.vuex-actions使用,10.vuex-重構購物車-準備Store,11.vuex-重構購物車-配置項(上午結束),vuex-getters定義-計算屬性,13.vuex-getters使用,14.vuex-modules定義-分模塊,15.分模塊-影響state取值方式,16.分模塊-命名空間,擴展: 使用Devtools調試vuex數據。
全套筆記資料代碼移步: 前往gitee倉庫查看
感興趣的小伙伴可以自取哦,歡迎大家點贊轉發~
vue指令(下)
v-for
基本使用
v-for 作用: 遍歷對象和數組
- 遍曆數組 (常用)
v-for="item in 數組名" item每一項
v-for="(item, index) in 數組名" item每一項 index下標
註意:item和index不是定死的,可以是任意的名字,但是需要註意 第一項是值 第二項是下標
- 遍歷對象 (一般不用)
<!--
v-for也可以遍歷對象(不常用)
v-for="(值, 鍵) in 對象"
-->
<ul>
<li v-for="value in user" :key="value">{{value}}</li>
</ul>
<ul>
<li v-for="(value, key) in user" :key="key">{{value}} ---{{key}}</li>
</ul>
- 遍曆數字
<!--
遍曆數字
語法: v-for="(item, index) in 數字"
作用:遍歷具體的次數 item從1開始 index下標從0開始的
-->
<ul>
<li v-for="(item, index) in 10" :key="item">{{item}} ---{{index}}</li>
</ul>
虛擬DOM 和 diff演算法
vue就地復用策略:Vue會儘可能的就地(同層級,同位置),對比虛擬dom,復用舊dom結構,進行差異化更新。
虛擬dom: 本質就是一個個保存節點信息, 屬性和內容的 描述真實dom的 JS 對象
diff演算法:
-
策略1:
先同層級根元素比較,如果根元素變化,那麼不考慮復用,整個dom樹刪除重建
先同層級根元素比較,如果根元素不變,對比出屬性的變化更新,並考慮往下遞歸復用。
-
策略2:
對比同級兄弟元素時,預設按照下標進行對比復用。
對比同級兄弟元素時,如果指定了 key,就會 按照相同 key 的元素 來進行對比。
v-for 的key的說明
-
設置 和 不設置 key 有什麼區別?
- 不設置 key, 預設同級兄弟元素按照下標進行比較。
- 設置了key,按照相同key的新舊元素比較。
-
key值要求是?
- 字元串或者數值,唯一不重覆
- 有 id 用 id, 有唯一值用唯一值,實在都沒有,才用索引
-
key的好處?
key的作用:提高虛擬DOM的對比復用性能
以後:只要是寫到列表渲染,都推薦加上 key 屬性。且 key 推薦是設置成 id, 實在沒有,就設置成 index
樣式處理
v-bind 對於class的增強
v-bind 對於類名操作的增強, 註意點, :class 不會影響到原來的 class 屬性
:class="對象/數組"
<template>
<div>
<!--
v-bind: 作用:設置動態屬性
v-bind針對 class和style 進行增強
允許使用對象或者數組
對象:如果鍵值對的值為true,那麼就有這個,否則沒有這個類
數組:數組中所有的類都會添加到盒子上
-->
<!-- <div class="box" :class="isRed ? 'red': ''">123</div> -->
<!-- <div class="box" :class="{red: isRed, pink: isPink}">123</div> -->
<div class="box" :class="arr">123</div>
</div>
</template>
v-bind對於style 的增強
<template>
<div>
<!--
:style也可以使用對象或者數組
-->
<div class="box" :style="[styleObj1, styleObj2]">123</div>
</div>
</template>
成績案例
基本結構與樣式
<template>
<div class="score-case">
<div class="table">
<table>
<thead>
<tr>
<th>編號</th>
<th>科目</th>
<th>成績</th>
<th>考試時間</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr >
<td>1</td>
<td>語文</td>
<td class="red">56</td>
<td>Tue Jun 07 2022 10:00:00 GMT+0800 (中國標準時間)</td>
<td><a href="#">刪除</a></td>
</tr>
<tr >
<td>2</td>
<td>數學</td>
<td>100</td>
<td>Tue Jun 07 2022 10:00:00 GMT+0800 (中國標準時間)</td>
<td><a href="#">刪除</a></td>
</tr>
</tbody>
<!-- <tbody >
<tr>
<td colspan="5">
<span class="none">暫無數據</span>
</td>
</tr>
</tbody> -->
<tfoot>
<tr>
<td colspan="5">
<span>總分:321</span>
<span style="margin-left:50px">平均分:80.25</span>
</td>
</tr>
</tfoot>
</table>
</div>
<div class="form">
<div class="form-item">
<div class="label">科目:</div>
<div class="input">
<input type="text" placeholder="請輸入科目" />
</div>
</div>
<div class="form-item">
<div class="label">分數:</div>
<div class="input">
<input type="text" placeholder="請輸入分數" />
</div>
</div>
<div class="form-item">
<div class="label"></div>
<div class="input">
<button class="submit" >添加</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ScoreCase',
data () {
return {
list: [
{id: 15, subject: '語文', score: 89, date: new Date('2022/06/07 10:00:00')},
{id: 27, subject: '數學', score: 100, date: new Date('2022/06/07 15:00:00')},
{id: 32, subject: '英語', score: 56, date: new Date('2022/06/08 10:00:00')},
{id: 41, subject: '物理', score: 76, date: new Date('2022/06/08 10:00:00')}
],
subject: '',
score: ''
}
}
};
</script>
<style lang="less">
.score-case {
width: 1000px;
margin: 50px auto;
display: flex;
.table {
flex: 4;
table {
width: 100%;
border-spacing: 0;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
th {
background: #f5f5f5;
}
tr:hover td {
background: #f5f5f5;
}
td,
th {
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
text-align: center;
padding: 10px;
&.red {
color: red;
}
}
}
.none {
height: 100px;
line-height: 100px;
color: #999;
}
}
.form {
flex: 1;
padding: 20px;
.form-item {
display: flex;
margin-bottom: 20px;
align-items: center;
}
.form-item .label {
width: 60px;
text-align: right;
font-size: 14px;
}
.form-item .input {
flex: 1;
}
.form-item input,
.form-item select {
appearance: none;
outline: none;
border: 1px solid #ccc;
width: 200px;
height: 40px;
box-sizing: border-box;
padding: 10px;
color: #666;
}
.form-item input::placeholder {
color: #666;
}
.form-item .cancel,
.form-item .submit {
appearance: none;
outline: none;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 10px;
margin-right: 10px;
font-size: 12px;
background: #ccc;
}
.form-item .submit {
border-color: #069;
background: #069;
color: #fff;
}
}
}
</style>
基本渲染
- v-for 渲染結構
- v-bind:class 控制樣式
<tbody>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.subject }}</td>
<td :class="{ red: item.score < 60 }">{{ item.score }}</td>
<td>{{ item.date }}</td>
<td><a @click.prevent="del(item.id)" href="#">刪除</a></td>
</tr>
</tbody>
刪除
刪除思路:
- 註冊點擊事件,傳遞參數,阻止預設行為
- 在method中提供對應函數
- 根據id刪除對應項
- 控制 tbody 展示
<tbody v-if="list.length">
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ index + 1 }}</td>
<td>{{ item.subject }}</td>
<td :class="{ red: item.score < 60 }">{{ item.score }}</td>
<td>{{ item.date }}</td>
<td><a @click.prevent="del(item.id)" href="#">刪除</a></td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="5">
<span class="none">暫無數據</span>
</td>
</tr>
</tbody>
methods: {
del (id) {
this.list = this.list.filter(item=>item.id !== id)
}
}
新增
添加思路:
- 獲取科目 和 分數
- 給添加按鈕註冊點擊事件
- 給list數組添加一個對象
- 重置表單數據
<div class="form">
<div class="form-item">
<div class="label">科目:</div>
<div class="input">
<input v-model.trim="subject" type="text" placeholder="請輸入科目" />
</div>
</div>
<div class="form-item">
<div class="label">分數:</div>
<div class="input">
<input v-model.number="score" type="text" placeholder="請輸入分數" />
</div>
</div>
<div class="form-item">
<div class="label"></div>
<div class="input">
<button class="submit" @click="submit">添加</button>
</div>
</div>
</div>
methods: {
submit () {
if (this.subject && (this.score >= 0 && this.score <= 100)) {
// 提交
this.list.push({
id: Math.random(),
subject: this.subject,
score: this.score,
date: new Date()
})
this.subject = ''
this.score = ''
} else {
alert('輸入內容不正確')
}
},
...
}
處理日期格式
- 安裝moment
yarn add moment
- 引入moment
import moment from 'moment'
- 定義格式化時間的函數
methods: {
// 格式化時間
formatDate(input) {
return moment(input).format('YYYY-MM-DD HH:mm:ss')
}
}
- 頁面中格式化使用
<td>{{ formatDate(item.date) }}</td>
計算屬性
基本使用
需求:翻轉字元串案例
計算屬性是一個屬性,寫法上是一個函數,這個函數的返回值就是計算屬性最終的值。
- 計算屬性必須定義在 computed 節點中
- 計算屬性必須是一個 function,計算屬性必須有返回值
- 計算屬性不能被當作方法調用,當成屬性來用
定義計算屬性
// 組件的數據: 需要計算的屬性
computed: {
reverseMsg () {
return this.msg.split('').reverse().join('')
}
}
使用計算屬性
<p>{{ reverseMsg }}</p>
計算屬性的緩存的問題
計算屬性: 緩存
計算屬性只要計算了一次,就會把結果緩存起來,以後多次使用計算屬性,直接使用緩存的結果,只會計算一次。
計算屬性依賴的屬性一旦發生了改變,計算屬性會重新計算一次,並且緩存
// 計算屬性只要計算了一次,就會把結果緩存起來,以後多次使用計算屬性,直接使用緩存的結果,只會計算一次。
// 計算屬性依賴的屬性一旦發生了改變,計算屬性會重新計算一次,並且緩存
export default {
data () {
return {
msg: 'hello'
}
},
computed: {
reverseMsg() {
console.log('我執行了')
return this.msg.split('').reverse().join('')
}
}
}
成績案例-計算屬性處理總分 和 平均分
- 在computed中提供計算屬性
computed: {
sumScore () {
return this.list.reduce((sum, item)=> sum + item.score, 0)
},
avgScore () {
return this.list.length ? (this.sumScore / this.list.length).toFixed(2) : 0
}
},
- 在模板中直接渲染計算屬性
<tfoot>
<tr>
<td colspan="5">
<span>總分:{{sumScore}}</span>
<span style="margin-left:50px">平均分:{{avgScore}}</span>
</td>
</tr>
</tfoot>
計算屬性的完整寫法
// 1. 計算屬性預設情況下只能獲取,不能修改。
// 2. 計算屬性的完整寫法
/*
computed: {
full() {},
full: {
get() {
return this.first + ' ' + this.last
},
set(value) {
}
}
}
*/
computed: {
full: {
get () {
...
},
set (value) {
...
}
}
}
大小選
目標: 完成全選和反選的功能
註意: 小選框都選中(手選/點反選), 全選自動選中
圖示:
標簽和數據準備(可複製):
<template>
<div>
<span>全選:</span>
<input type="checkbox" />
<button >反選</button>
<ul>
<li >
<input type="checkbox" />
<span>名字</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
arr: [
{
name: "豬八戒",
c: false,
},
{
name: "孫悟空",
c: false,
},
{
name: "唐僧",
c: false,
},
{
name: "白龍馬",
c: false,
},
],
};
}
};
</script>
<style>
</style>
正確答案(不可複製):
<template>
<div>
<span>全選:</span>
<!-- 4. v-model 關聯全選 - 選中狀態 -->
<input type="checkbox" v-model="isAll"/>
<button @click="btn">反選</button>
<ul>
<li v-for="(obj, index) in arr" :key="index">
<!-- 3. 對象.c - 關聯 選中狀態 -->
<input type="checkbox" v-model="obj.c"/>
<span>{{ obj.name }}</span>
</li>
</ul>
</div>
</template>
<script>
// 目標: 小選框 -> 全選
// 1. 標簽+樣式+js準備好
// 2. 把數據迴圈展示到頁面上
export default {
data() {
return {
arr: [
{
name: "豬八戒",
c: false,
},
{
name: "孫悟空",
c: false,
},
{
name: "唐僧",
c: false,
},
{
name: "白龍馬",
c: false,
},
],
};
},
// 5. 計算屬性-isAll
computed: {
isAll: {
set(val){
// 7. 全選框 - 選中狀態(true/false)
this.arr.forEach(obj => obj.c = val)
},
get(){
// 6. 統計小選框狀態 -> 全選狀態
return this.arr.every(obj => obj.c === true)
}
}
},
methods: {
btn(){
// 8. 讓數組裡對象的c屬性取反再賦予回去
this.arr.forEach(obj => obj.c = !obj.c)
}
}
};
</script>
<style>
</style>
屬性監聽
基本使用
當需要監聽某個數據是否發生改變,就要用到watch
/*
watch: {
// 只要屬性發生了改變,這個函數就會執行
屬性: function () {
}
}
*/
watch: {
// 參數1: value 變化後的值
// 參數2: oldValue 變化前的值
msg (value, oldValue) {
console.log('你變了', value, oldValue)
}
}
複雜類型的監聽-監聽的完整寫法
如果監聽的是複雜數據類型,需要深度監聽,需要指定deep為true,需要用到監聽的完整的寫法
// 1. 預設情況下,watch只能監聽到簡單類型的數據變化,如果監聽的是複雜類型,只會監聽地址是否發生改變,不會監聽對象內部屬性的變化。
// 2. 需要使用監聽的完整寫法 是一個對象
watch: {
// friend (value) {
// console.log('你變了', value)
// }
friend: {
// handler 數據發生變化,需要執行的處理程式
// deep: true 如果true,代表深度監聽,不僅會監聽地址的變化,還會監聽對象內部屬性的變化
// immediate: 立即 立刻 是否立即監聽 預設是false 如果是true,代表頁面一載入,會先執行一次處理程式
handler (value) {
console.log('你變了', value)
},
deep: true,
immediate: true
}
},
成績案例-監聽數據進行緩存
- 監聽list的變化
watch: {
list: {
deep: true,
handler() {
localStorage.setItem('score-case', JSON.stringify(this.list))
}
}
},
- 獲取list數據的時候不能寫死,從localStorage中獲取
data() {
return {
list: JSON.parse(localStorage.getItem('score-case')) || [],
subject: '',
score: '',
}
},
vscode斷點調試(自學)
前言:作為前端開發,我們經常會遇到代碼錯誤,需要進行調試
常見的調試方案:
- 不調試,直接看代碼找問題
- console.log 列印日誌
- 用 VSCode 的 debugger 來調試 (斷點調試)
前兩種,適合找一些簡易的錯誤,如果短時間錯誤沒有排查出來,建議使用 vscode斷點調試。
配置步驟 (兩步)
-
新建
.vscode
目錄,launch.json
文件, 填入配置內容註意:
埠號
需要和 啟動伺服器埠號
統一
{
"configurations": [
{
"name": "Launch Chrome",
"request": "launch",
"type": "pwa-chrome",
"url": "
"sourceMapPathOverrides": {
"webpack://src/*": "${workspaceFolder}/src/*"
}
}
]
}
效果如下圖:
vue.config.js
填入配置內容
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// -----------------------------------------------------------
configureWebpack: config => {
// 配置斷點調試,實際上線時,可刪除
config.output.devtoolModuleFilenameTemplate = info => {
const resPath = info.resourcePath
return `webpack://${resPath}`
}
}
// -----------------------------------------------------------
})
效果如下:
兩個配置加完,重新啟動伺服器,就可以在vscode源代碼中進行斷點調試啦!
使用演示
- 代碼行號前面,點擊打上斷點
- 啟動伺服器
- 開始調試
- 效果預覽
- 左側還有變數,監視,調用堆棧等,可以自行參考使用 (可選)