【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)

coderwhy前端系统课 - 阶段六VUE (整理版)(更新中2023.10.23)

1. 前言

本文以coderwhy前端系统课 - 阶段六VUE为主。

一刷版本的笔记有些乱,目前还在二刷整理,同时参考了一部分其他的资料,并加上个人使用总结

暂时停更,在备考,考完分享《软考中级-软件评测师》的复习资源和笔记
-----2023-10-23

建议使用 资源绑定链接 里的html文件进行阅读

直接下载

资源说明:

  1. 资源内有自定义的样式更便于阅读,这里的样式不做额外编写
  2. 资源内点击侧边栏开关时文章阅读位置会偏移,点击目录定位即可
  3. 资源内的图片无法像csdn的可以点击放大,但能看清的
  4. 该文章有些定位点链接,资源内可点击,文章这点了没效果,不做额外修改
  5. 该文章出现一些看不懂的符号拼接啥的,略过
    (一些自定义语法,太多了,这回应该删完了,后面更新估计懒得删)

----2023.10.23 更新----

  1. 图片经停1秒会放大显示
    (会有文章抖动现象,vscode的md目前没有像csdn的可以点击放大图片)

附上一张效果图:
【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第1张图片

2. vue2 vs vue3

放在开头为了方便对比,后面的内容以vue3为主

2.1. vue文件结构

/.wrap2 <
/.box <

vue2

<template>
  <div>
    <h1>{{ title }}h1>
    <button @click="increment">{{ count }}button>
  div>
template>

<script>
export default {
  data() {
    return {
      title: 'Hello, Vue2!',
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
script>

/->
/.box <

vue3

<template>
  <div>
    <h1>{{ title }}h1>
    <button @click="increment">{{ count }}button>
  div>
template>

<script>
import { ref } from 'vue'

export default {
  data() {
    return {
      // 也可以在这定义data数据
    }
  },
  setup() {
    const title = 'Hello, Vue3!'
    const count = ref(0)

    function increment() {
      count.value++
    }

    return {
      title,
      count,
      increment
    }
  }
}
script>

/->
/->

2.2. 路由

– 来自chatgpt,两者都使用Vue Router来实现路由功能

/.wrap2 <
/.box <

vue2

  1. 引入Vue Router插件及其依赖
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
  1. 配置路由映射关系
const router = new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
  ]
})

其中,path表示URL路径,name为路由名称,component指定该路由对应的组件。

  1. 将路由挂载到Vue实例上
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

在 Vue3 中,render 函数的写法有所不同,使用了新的 createApp API。

/->
/.box <

vue3

提供了一个基于函数式API的新特性:createRouter()

  1. 引入Vue Router插件及其依赖
import { createRouter, createWebHistory } from 'vue-router'
  1. 创建Router实例并配置路由映射关系
const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: About
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

与Vue2不同的是,在Vue3中,需要将history传递给 createWebHistory 来指定路由模式。

routes 数组中的每个对象包含pathnamecomponent属性。

  1. 将路由挂载到Vue实例上
createApp(App).use(router).mount('#app')

这里使用createApp()方法来创建Vue实例,并通过use()方法将router实例添加到Vue实例中。

/->
/->

备注

vue2 中的 render: h => h(App)

【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第2张图片

2.3. JS函数

3. 基础语法

3.1. 插值语法 {{}}

/.wrap2 <
/.box <

html


<h2>{{ message }}h2>
<h2>当前计数: {{ counter }} h2>


<h2>计数双倍: {{ counter * 2 }}h2>
<h2>展示的信息: {{ info.split(" ") }}h2>


<h2>{{ age >= 18? "成年人": "未成年人" }}h2>


<h2>{{ formatDate(time) }}h2>

/->
/.box <

javascript

 //data
 counter: 100,
 info: "my name is why",
 age: 22,
 time: 123
 //method
 formatDate: function(date) {
   return "2022-10-10-" + date
 }

/->/->

3.2. 内置指令

  • v-for(item in list) 遍历,内容:{{item}}
  • v-text 文本 ,等于直接用 {{}}
  • v-html  HTML插入
  • v-pre  无需编译,如{{m}},显示在浏览器还是 {{m}}
  • v-once  只传入一次
  • v-cloak 遮罩斗篷,先隐藏没有传入值的{{m}},有传入值后显示,css加上 [v-cloak]{display:none}
(1) v-memo 某值改变才更新

某值改变时才更新内容,可查看《vue3.2新增指令v-memo的使用 - 南风晚来晚相识》

/.wrap2 <
/.box <

html

<div id="app">
  <div v-memo="[name]">
    <h2>姓名: {{ name }}h2>
    <h2>年龄: {{ age }}h2>
    <h2>身高: {{ height }}h2>
  div>
  <button @click="updateInfo">改变信息button>
div>

/->
/.box <

javascript

data: function() {
  return {
    name: "why",
    age: 18,
    height: 1.88
  }
},

methods: {
  updateInfo: function() {
    this.name = "kobe"
    this.age = 20
  }
}

/->/->

(2) v-bind 动态绑定 :
原语句 语法糖
v-bind:src="" :src
v-bind:href="" :href
v-bind:class="" :class

绑定方法参考

/.wrap2 <
/.box lit3<

html


<img v-bind:src="showImgUrl" alt="">

<img :src="showImgUrl" alt="">


<a :href="href">百度一下a>

/->
/.box lit7<

javascript

data: function() {
  return {
    imgUrl1: "http://p1.music.126.net/agGc1qkogHtJQzjjyS-kAA==/109951167643767467.jpg",
    imgUrl2: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",

    showImgUrl: "http://p1.music.126.net/_Q2zGH5wNR9xmY1aY7VmUw==/109951167643791745.jpg",
    href: "http://www.baidu.com"
  }
},

methods: {
  switchImage: function() {
    //  图片地址 =  现在的图片地址 ===  是图片1吗 ?     是:展示图片2  不是:显示图片1
    this.showImgUrl = this.showImgUrl === this.imgUrl1 ? this.imgUrl2: this.imgUrl1
  }
}

/->/->

❥ 绑定class

/.wrap2 <
/.box lit3<

前提:

 // css
 .active {
      color: red;
    }
 //data
 isActive: false,
   // methods
    btnClick: function() {
       this.isActive = !this.isActive
    },

/->
/.box lit7<

  1. 三元:
  
  <button :class="isActive ? 'active': ''" @click="btnClick">我是按钮button>
  1. 单值 ⭐

<button class="haha" :class="{ active: isActive }" @click="btnClick">我是按钮button>
  1. 对象语法的多个键值对

<button :class="{ active: isActive, why: true, kobe: false }" @click="btnClick">我是按钮button>
  1. 把 :class 的内容抽取出去

<button class="abc cba" :class="getDynamicClasses()" @click="btnClick">我是按钮button>
 //method
 getDynamicClasses: function() {
   return { active: this.isActive, why: true, kobe: false }
 }
  1. 数组
    
    <h2 :class="['abc', 'cba']">Hello Arrayh2>
    <h2 :class="['abc', className]">Hello Arrayh2>
    <h2 :class="['abc', className, isActive? 'active': '']">Hello Arrayh2>
    <h2 :class="['abc', className, { active: isActive }]">Hello Arrayh2>

/->/->

❥ 绑定style
  1. 绑定属性为对象,分隔符为,

<h2 style="color: red; font-size: 30px;">哈哈哈哈h2>



<h2 v-bind:style="{ color: fontColor, fontSize: fontSize + 'px', height: '88px' }">哈哈哈哈h2>
//data
fontColor: "blue",
  1. 绑定属性为数组 (很少用)
<h2 :style="objStyle">呵呵呵呵h2>
<h2 :style="[objStyle, { backgroundColor: 'purple' }]">嘿嘿嘿嘿h2>
//data
objStyle: {
  fontSize: '50px',
  color: "green"
}
❥ 绑定属性名
<h2 :[name]="'aaaa'">Hello Worldh2>
//data
name: "class"
❥ 绑定对象
<h2 v-bind="infos">Hello Bindh2>
// data
infos: { name: "why", age: 18, height: 1.88, address: "广州市" },
(3) v-on 事件绑定(事件监听) @
原语句 语法糖
v-on:click=" " @click=" "

绑定方法参考

/.wrap2 <
/.box lit7<


<div class="box" v-on:click="divClick">div>


<div class="box" @click="divClick">div>


<div class="box" @mousemove="divMousemove">div>


<div class="box" @click="divClick" @mousemove="divMousemove">div>

/->
/.box lit3<

methods: {
  divClick() {
    console.log("divClick")
  },
  divMousemove() {
    console.log("divMousemove")
  }
}

/->/->

❥ 参数传递

/.wrap2 <
/.box <


<button @click="btn1Click">按钮1button>


<button @click="btn2Click('pyy', age)">按钮2button>


<button @click="btn3Click('pyy', age, $event)">按钮3button>

/->
/.box <

//data
age: 18
//方法 
methods: {
  // 1.默认参数: event对象
  // 总结: 如果在绑定事件的时候, 没有传递任何的参数
  //       那么event对象会被默认传递进来
  btn1Click(event) {
    console.log("btn1Click:", event)
  },

  // 2.明确参数:
  btn2Click(name, age) {
    console.log("btn2Click:", name, age) // pyy 18
  },

  // 3.明确参数+event对象
  btn3Click(name, age, event) {
    console.log("btn3Click:", name, age, event)
  }
}

/->/->

❥ 添加修饰符
<button @click.stop="btnClick">按钮button>

使用过

/.wrap2 <
/.box lit3<

回车自动触发:@keyup.enter.native
阻止默认事件:@submit.native.prevent

/->
/.box lit7<

解决问题:
【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第3张图片

/->/->

其他修饰符

  • .stop - 调用 event.stopPropagation(),这是阻止事件的冒泡方法,不让事件向document上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开,解释来源
  • .prevent - 调用event.preventDefault(),这是阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素;
  • .capture - 添加事件侦听器时使用 capture 模式,事件冒泡
  • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调
  • .{keyAlias} - 仅当事件是从特定键触发时才触发回调
  • .once - 只触发一次回调
  • .left - 只当点击鼠标左键时触发
  • .right - 只当点击鼠标右键时触发
  • .middle - 只当点击鼠标中键时触发passive -{ passive: true}模式添加侦听器
(4) v-if 是否(条件渲染)

v-if="条件"     条件成立,执行该段
v-else       条件不成立,执行该段

❥ 数组

/.wrap2 <
/.box <

 <ul v-if="names.length > 0">
   <li v-for="item in names">{{item}}li>
 ul>
 <h2 v-else>当前names没有数据, 请求获取数据后展示h2>

v-for(元素 in 列表)  遍历

/->
/.box <

 //data
 names:[]  // 无数据
 names:[ab, ad, ae] // 有数据

/->/->

❥ 对象

/.wrap2 <
/.box <


<div class="info" v-if="Object.keys(info).length">  
  <h2>个人信息h2>
  <ul>
    <li>姓名: {{info.name}}li>
    <li>年龄: {{info.age}}li>
  ul>
div>


<div v-else>
  <h2>没有输入个人信息h2>
  <p>请输入个人信息后, 再进行展示~p>
div>

/->
/.box <

info: {name:"aa", age:11}

/->/->

❥ if else if
  <div id="app">
    <h1 v-if="score > 90">优秀h1>
    <h2 v-else-if="score > 80">良好h2>
    <h3 v-else-if="score >= 60">及格h3>
    <h4 v-else>不及格h4>
  div>
(5) v-show 显示/隐藏 (条件渲染)

/.wrap2 <
/.box <

<div>
  <button @click="toggle">切换button>
div>

<div v-show="isShowCode">
  <img src="https://game.gtimg.cn/images/yxzj/web201706/images/comm/floatwindow/wzry_qrcode.jpg" alt="">
div>

/->
/.box <

// data
isShowCode: true
//method
toggle() {
  this.isShowCode = !this.isShowCode
}

/->
/->

注意:
v-if=true/false也可以控制元素的隐藏显示,区别在于:

  • v-show 不支持 template (见template详解)
  • v-show 不可以和 v-else 一起使用
  • v-show 不管是 true 还是 false ,内容的 dom 都是存在的,只是通过 css 的 display 属性来切换
  • v-if=flase 时,对应的内容不会渲染在 dom 中(是不存在的!
  • 频繁的切换隐藏显示用v-show
(6) v-for 遍历 (列表渲染)

v-for="(item,index) in 数组"

也支持 v-for="(item,index) of 数组",但平时一般直接用in

《v-for 循环中 in 与 of 区别,以及 ES5 for in 与 ES6 for of 区别 - 雁 南飞》:

【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第4张图片

❥ 数组和对象

/–遍历对象 v-for="(value, key, index) in info"

/–遍历字符串 v-for="item in message"

/–遍历数字 v-for="item in 100"

写在 li 标签,会产生多个 li,默认 item 为 value 值

/.wrap2 <
/.box lit4 <

html


<li v-for="movie in movies">{{ movie }}li>


<li v-for="(value, key, index) in info">
  {{value}}-{{key}}-{{index}}
li>


<li v-for="(movie, index) in movies">
  {{index + 1}} - {{ movie }}
li>


<h2>商品列表h2>
<div class="item" v-for="item in products">
  <h3 class="title">商品: {{item.name}}h3>
  <span>价格: {{item.price}}span>
  <p>秒杀: {{item.desc}}p>
div>
div>

/->
/.box lit6 <

javascript

 // data
 // 1.movies
 movies: ["星际穿越", "少年派", "大话西游", "哆啦A梦"],
 
 // 2.数组: 存放的是对象
 products: [
   { id: 110, name: "Macbook", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
   { id: 111, name: "iPhone", price: 8.8, desc: "9.9秒杀, 快来抢购!" },
   { id: 112, name: "小米电脑", price: 9.9, desc: "9.9秒杀, 快来抢购!" },
 ]

/->
/->

❥ 数组更新检测
 changeArray() {
   // 1.直接将数组修改为一个新的数组
   // this.names = ["why", "kobe"]
 
   // 2.通过一些数组的方法, 修改数组中的元素
   this.names.push("why")    // 加
   this.names.pop()          // 删除后面一个
   this.names.splice(2, 1, "why")
   this.names.sort()
   this.names.reverse()
 
   // 3.不修改原数组的方法是不能侦听(watch)
    // 因为this.names.map() 会产生一个新数组,而不是修改原数组,所以需要把值存入一个变量
   const newNames = this.names.map(item => item + "why")  //每个value后面拼接why    
   this.names = newNames
 }

⭐ splice!可以添加、删除、替换

names.splice(3,1,"pyy","pyyyy") // 在位置3 删除1个 添加pyy和pyyyy
❥ key的作用

官方解释key::
在这里插入图片描述

有key和没有key时执行的方法不一样
【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第5张图片

没key时,也会执行diff算法,对比遇到不一样的内容时,后面的全部替换:

有key时,也使用diff算法,但会尽量的复用原有节点:
【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第6张图片


<li v-for="item in letters" :key="item">{{item}}li>

总结
【coderwhy前端笔记 - 阶段六 VUE 】(整理版)(更新中2023.7.16)_第7张图片

key的面试问答

(7) template (列表渲染)

当div没有意义,又使用了v-xxx,那就把 div 换成 template
可以放id