【前端Vue】Vue從0基礎完整教程第2篇:day-08【附程式碼文件】

程序员一诺yinuo發表於2024-03-14

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 作用: 遍歷物件和陣列

  1. 遍歷陣列 (常用)
v-for="item in 陣列名"  item每一項
v-for="(item, index) in 陣列名"  item每一項 index下標

注意:item和index不是定死的,可以是任意的名字,但是需要注意 第一項是值  第二項是下標
  1. 遍歷物件 (一般不用)
<!--
  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>
  1. 遍歷數字
<!-- 
  遍歷數字
  語法: 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的說明

  1. 設定 和 不設定 key 有什麼區別?

    • 不設定 key, 預設同級兄弟元素按照下標進行比較。
    • 設定了key,按照相同key的新舊元素比較。
  2. key值要求是?

    • 字串或者數值,唯一不重複
    • 有 id 用 id, 有唯一值用唯一值,實在都沒有,才用索引
  3. 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>

成績案例

image-20220605053557169

基本結構與樣式

<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>

基本渲染

  1. v-for 渲染結構
  2. 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>

刪除

刪除思路:

  1. 註冊點選事件,傳遞引數,阻止預設行為
  2. 在method中提供對應函式
  3. 根據id刪除對應項
  4. 控制 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)
  } 
}

新增

新增思路:

  1. 獲取科目 和 分數
  2. 給新增按鈕註冊點選事件
  3. 給list陣列新增一個物件
  4. 重置表單資料
<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>

計算屬性

基本使用

需求:翻轉字串案例

計算屬性是一個屬性,寫法上是一個函式,這個函式的返回值就是計算屬性最終的值。

  1. 計算屬性必須定義在 computed 節點中
  1. 計算屬性必須是一個 function,計算屬性必須有返回值
  1. 計算屬性不能被當作方法呼叫,當成屬性來用

定義計算屬性

// 元件的資料: 需要計算的屬性
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) {
      ...
    }
  }
}

大小選

目標: 完成全選和反選的功能

注意: 小選框都選中(手選/點反選), 全選自動選中

圖示:

7.5_案例_全選和反選

標籤和資料準備(可複製):

<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斷點除錯

image-20220603234332440

配置步驟 (兩步)

  1. 新建 .vscode 目錄, launch.json 檔案, 填入配置內容

    注意:埠號 需要和 啟動伺服器 埠號 統一

{
  "configurations": [
    {
      "name": "Launch Chrome",
      "request": "launch",
      "type": "pwa-chrome",
      "url": "
      "sourceMapPathOverrides": {
        "webpack://src/*": "${workspaceFolder}/src/*"
      }
    }
  ]
}

效果如下圖:

image-20220603233902480

  1. 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}`
    }
  }
  // -----------------------------------------------------------
})

效果如下:

image-20220603234122367

兩個配置加完,重新啟動伺服器,就可以在vscode原始碼中進行斷點除錯啦!

使用演示

  1. 程式碼行號前面,點選打上斷點

image-20220603234435355

  1. 啟動伺服器

image-20220603234739226

  1. 開始除錯

image-20220603234836207

  1. 效果預覽

image-20220603235019255

  1. 左側還有變數,監視,呼叫堆疊等,可以自行參考使用 (可選)

未完待續, 同學們請等待下一期

全套筆記資料程式碼移步: 前往gitee倉庫檢視

感興趣的小夥伴可以自取哦,歡迎大家點贊轉發~

相關文章