VUE3学习

时间:2024-05-10 20:55:59

VUE学习

文章目录

  • VUE学习
    • 前置知识
      • ES6模块化
        • node.js 中如何实现模块化
        • 前端模块化规范
        • ES6模块化规范
        • 在node.js中体验ES6模块化
        • ES6模块化的基本语法
      • Promise
        • Promise 的基本概念
        • 基于 then-fs 读取文件内容
        • 基于 Promise 封装读文件的方法
      • async/await 简化 Promise调用
      • EventLoop
        • JavaScript 是单线程的语言
        • 同步任务和异步任务
      • 宏任务和微任务
      • API接口案例
      • webpack
        • webpack基本概念
          • 环境准备
        • webpack使用步骤
        • webpack开发服务器
    • Vue
      • vue安装
      • Vue创建项目
      • vue自定义配置
      • eslint
      • 单Vue文件开发
      • Vue语法
        • 插值表达式
        • MVVM设计模式
        • 指令
          • 给标签属性设置Vue变量的值
          • 给标签绑定事件
          • 获取表单的值
          • 更新DOM对象的innerText/innerHTML
          • 标签隐藏,出现
          • v-for
            • DOM
          • 动态class
          • 动态style
        • 计算属性computed
        • 侦听器watch
      • 组件
        • 基础使用
        • 组件通信
        • 生命周期
          • 钩子函数
        • 组件属性
          • $refs 获取组件对象
          • $nextTick 等DOM异步更新后,触发函数
          • 组件 name 属性
          • 动态组件
            • 组件缓存
          • 组件插槽
      • 自定义指令
        • 自定义指令注册
        • 自定义指令传值
      • axios
      • 路由
        • 组件分类
        • vue-router
          • 使用
          • 声明式导航
          • 路由重定向
          • 路由404
          • 路由模式设置
          • 编程式导航
          • 路由嵌套
          • 路由守卫
      • Vant移动端组件库
    • Vuex
      • 基础功能
        • Store
        • mutations
        • actions
        • getters
        • 模块化 module
          • 模块化中的命名空间 `namespaced`
    • Element-UI
        • 表单
          • 表单校验的先决条件
          • 表单校验规则
          • 手动校验的实现
    • VUE3
      • **社区生态**
      • vite
      • vue3
        • 创建Vue应用
        • 选项API
        • 组合式API
          • `setup()`
          • 生命周期
          • `reactive()`函数
          • toRef()
          • toRefs()
          • ref()
          • computed()
          • watch()
          • ref属性
          • 组件通信
    • 果用于子组件,引用将是子组件的实例
          • 组件通信

前置知识

ES6模块化

node.js 中如何实现模块化

node.js 遵循 CommonJS 的模块化规范

  • 导入其他模块使用 require()方法
  • 模块对外共享成员使用 module.exports对象
前端模块化规范

ES6 模块化之前,JavaScript 社区提出 AMD、CMD、CommonJS 等模块化规范,这些社区提出的模块化标准,存在一定的差异性与局限性,并不是浏览器与服务器通用的模块化标准

ES6模块化是官方的通用规范

ES6模块化规范

ES6模块化规范是浏览器与服务器端通用的模块开发规范

  • 每个js文件都是一个独立的模块
  • 导入其他模块成员使用import关键字
  • 向外共享模块成员使用export关键字
在node.js中体验ES6模块化

node.js中默认仅支持CommonJS模块化规范,若想基于 node.js 体验与学习ES6的模块化语法,按照如下两个步骤进行配置

  • node -v确保安装 v14.15.1或更高版本的node.js
  • package.json 的根节点中添加"type":"module"节点

npm init -y快速初始化package.json包管理文件

image-20240501105215776

ES6模块化的基本语法
  • 默认导出与默认导入

    • 默认导出语法:export default 默认导出的成员
    • 每个模块中,只允许使用唯一的一次默认导出
    • image-20240501105921084
    • 默认导入语法:import 接收名称 from '模块标识符'
    • 默认导入时的接收名称可以是任意名称,只要是合法的成员名称即可
    • image-20240501110218227
  • 按需导出与按需导入

    • 按需导出语法:export 按需导出的成员
    • image-20240501111340089
    • 按需导入语法:import {s1,s2,say} from '模块标识符'
    • image-20240501111407575
    • 每个模块中可以使用多次按需导出
    • 按需导入的成员名称必须和按需导出的名称保持一致
    • 按需导入时,可以使用 as关键字进行重命名
    • 按需导入可以和默认导入一起使用
  • 直接导入并执行模块中代码

    如果只想单纯地执行某个模块中的代码,并不需要模块中向外共享的成员,此时,可以直接导入并执行模块代码

    • import '模块标识符'直接导入并执行模块中的代码

Promise

Promise 的基本概念
  • Promise 是一个构造函数
    • 可以创建 Promise 的实例const p = new Promise()
    • new 出来的 Promise 实例对象,代表一个异步操作
  • Promise.prototype上包含一个.then()方法
    • 每一次 new Promise()构造函数得到的实例对象
    • 都可以通过原型链的方式访问到.then()方法
  • .then()方法用来预先指定成功和失败的回调函数
    • p.then(成功的回调函数,失败的回调函数)
    • p.then(result->{},error=>{})
    • 调用.then()方法时,成功的回调函数时必选的、失败的回调函数是可选的
    • 如果上一个.then()方法返回一个新的 Promise 实例对象,则可以通过下一个.then()继续进行处理。通过.then()方法的链式调用,就能解决回调地狱的问题
  • .catch()捕获错误
    • 在Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.cath 方法进行捕获和处理
    • 如果不希望前面的错误导致后续的.then()无法正常执行,则可以将.catch()的调用提前
  • Promise.all()方法
    • Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then()操作
  • Promise.race()方法
    • 发起并行的Promise异步操作,只要任何一个异步操作完成,就立即执行下一步的.then()操作
import thenfs from "then-fs";

const promiseArr = [
  thenfs.readFile("./files/1.txt", "utf8"),
  thenfs.readFile("./files/2.txt", "utf8"),
  thenfs.readFile("./files/3.txt", "utf8"),
]
// 全部异步完成
Promise.all(promiseArr).then(res=>{
  console.log(res)
})
// 任意一个异步完成
Promise.race(promiseArr).then(res=>console.log(res))
基于 then-fs 读取文件内容

由于 node.js 官方提供的 fs 模块仅支持以回调函数的方式读取文件,不支持 Promise 的调用方式。因此,需要先运行如下命令npm install then-fs,安装 then-fs 这个第三方包,从而支持基于 Promise 的方式读取文件的内容:

  • then-fs 的基本使用

调用 then-fs 提供的 readFile()方法,可以异步地读取文件的内容,它的返回值是 Promise 的实例对象。因此可以调用 .then()方法为每个 Promise 异步指定成功和失败之后的回调函数

import thenfs from "then-fs";

thenfs.readFile("./files/1.txt", "utf8").then((r1) => {
  console.log(r1);
  return thenfs.readFile("./files/2.txt", "utf8");
}).then((r2) => {
  console.log(r2);
  return thenfs.readFile("./files/3.txt", "utf8");
}).then((r3) => {
  console.log(r3);
}).catch((err)=>{
  console.log(err)
});;

image-20240501183905150

基于 Promise 封装读文件的方法

方法的封装要求:

  • 方法名要定义为getFile
  • 方法接收一个形参path,表示要读取的文件的路径
  • 方法的返回值为 Promise 实例对象
import fs from "fs";

export function getFile(path) {
  // 要创建具体的异步操作,需要在new Promise()构造函数期间,传递一个 function 函数,将具体异步操作定义到 function 函数内部
  return new Promise(function (resolve, reject) {
    fs.readFile(path, "utf8", (err, dataStr) => {
      if (err) return reject(err);//读取失败,调用失败的回调函数
      resolve(dataStr);//读取成功,调用成功的回调函数
    });
  });
}

getFile('./files/1.txt').then(res=>console.log(res)).catch(err=>console.log(err))
getFile('./files/11.txt').then(res=>console.log(res)).catch(err=>console.log(err))

async/await 简化 Promise调用

  • async标记函数时异步,不会阻塞其他的流程
  • await强制等待,必须和 async配合使用

async/await 是 ES8 引入的新语法,用来简化 Promise 异步操作。在 async/await 出现之前,开发者只能通过链式.then()方式处理Promise异步操作

  • async/await 的基本操作

     import thenFs from 'then-fs'
    
    // 按照顺序读取文件 1 2 3 的内容
    async function getAllFile(){
      const r1 = await thenFs.readFile('./files/1.txt','utf8')
      console.log(r1)
    
      const r2 = await thenFs.readFile('./files/2.txt','utf8')
      console.log(r2)
    
      const r3 = await thenFs.readFile('./files/3.txt','utf8')
      console.log(r3)
    }
    
    getAllFile()
    
  • 注意事项

    • 如果在 function 中使用了 await ,则 function 必须被 async 修饰

    • 在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行

    • import thenFs from 'then-fs'
      
      // 按照顺序读取文件 1 2 3 的内容
      async function getAllFile(){
      
        console.log('B')
        // awit 之后的内容会异步执行,方法调用会在此处返回
        const r1 = await thenFs.readFile('./files/1.txt','utf8')
        const r3 = await thenFs.readFile('./files/3.txt','utf8')
        const r2 = await thenFs.readFile('./files/2.txt','utf8')
        console.log(r1,r2,r3)
      
        console.log('D')
      }
      console.log('A')
      getAllFile()
      console.log('C')
      

EventLoop

JavaScript 是单线程的语言

同一时间只能做一件事情

image-20240501192655843

单线程执行任务队列的问题:

如果前一个任务非常耗时,则后续的任务就不得不一直等待,从而导致程序假死的问题

同步任务和异步任务

为了防止某个耗时任务导致程序假死的问题,JavaScript把待执行的任务分为了两类:

  • 同步任务
    • 非耗时任务,指的是在主线程上排队执行的那些任务
    • 只有前一个任务执行完毕,才能执行后一个任务
  • 异步任务
    • 耗时任务,异步任务由JavaScript委托给宿主环境进行执行
    • 当异步任务执行完成后,会通知 JavaScript 主线程执行异步任务的回调函数
  • 同步任务和异步任务的执行过程
    • image-20240501193539862
    • 1、同步任务由 JavaScript 主线程依次执行
    • 2、异步任务委托给宿主环境执行
    • 3、已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
    • 4、JavaScript 主线程的执行栈被清空后,会读取任务队列中的回调函数,依次执行
    • 5、JavaScript 主线程不断重复第4步

宏任务和微任务

JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类

image-20240501200610979

  • 宏任务

    • 异步 Ajax 请求
    • setTimeout、setInterval
    • 文件操作
    • 其他宏任务
  • 微任务

    • Promise.then、.catch、.finally
    • process.nextTick
    • 其他微任务
  • 宏任务和微任务的执行顺序

image-20240501200646375

API接口案例

基于MySQL数据库 + Express 对外提供用户列表API接口服务

  • 相关技术
    • 第三方包 express 和 mysql2
    • ES6 模块化
    • Promise
    • async/await
  • 主要步骤
  • npm install -g nodemon 启动服务需要
    • 搭建项目基本结构
      • npm init -y
      • 启用ES6模块化支持,在 package.json 中声明 “type”:“module”
      • 安装第三方依赖包 npm install express@4.17.1 mysql2@2.2.5
    • 创建基本的服务器
    • 创建 db 数据库模块
    • 创建 user_ctrl 业务模块
    • 创建 user_router 路由模块
    • 使用try...catch捕获异常

webpack

webpack基本概念
  • 一个第三方模块包,用于分析,并打包代码
    • 支持所有类型文件的打包
    • 支持 less/sass=>css
    • 支持ES6/7/8=>ES5
  • 识别代码,翻译,压缩,整合打包
  • 提高打开网站的速度
环境准备
  • npm install -g yarn安装yarn

  • 初始化包环境yarn init创建一个package.json

  • 安装依赖包yarn add webpack webpack-cli -D

  • package.json 中自定义打包命令 "scripts": {"build":"webpack"},

webpack使用步骤
  • 打包

webpack默认打包入口在src/index.js,执行自定义的 yarn build命令打包,打包时终端要位于src的父级文件夹,打包生成 dist文件夹

  • webpack入口出口修改
    • 新建 webpack.config.js
    • 填入配置
    • 修改入口文件名

配置文档:http://webpack.docschina.org/concepts/#entry

  • yarn build 执行流程

image-20240501215749358

  • 插件自动生成html文件

    http://webpack.docschina.org/plugins/html-webpack-plugin

    • npm install --save-dev html-webpack-plugin
    • webpack.config.js添加配置
  • 打包css文件

    css-loader ,让webpack能处理css类型文件:http://webpack.docschina.org/loaders/css-loader/

    style-loader,把css插入到DOM中 :https://webpack.docschina.org/loaders/style-loader/

    • 安装依赖
    • 添加配置
  • 处理 less 文件

    less-loader,webpack 将 Less 编译为 CSS 的 loader: https://webpack.docschina.org/loaders/less-loader/

  • 处理图片,字体图标

    webpack5,使用assert module技术实现字体文件和图片文件处理,无需配置额外loader

    https://webpack.docschina.org/guides/asset-modules/

    小于8kb的图片,直接转base64放在js文件中

    大于8kb,单独存放

  • babel降级JS语法,兼容低版本浏览器

    babel官网:http://www.babeljs.cn/

    babel-loader:https://webpack.docschina.org/loaders/babel-loader/

webpack开发服务器
  • 每次修改代码,重新打包,才能看到最新效果,实际工作中打包耗时

    webpack开发服务器,把代码运行在内存中,自动更新,实时返回给浏览器显示

    webpack-dev-server文档:https://webpack.docschina.org/configuration/dev-server/

    1、下载依赖yarn add webpack-dev-server -D

    2、自定义webpack开发服务器启动命令 serve - 在package.json

    "scripts":{"serve":"webpack serve"}

    3、当前项目启动webpack开发服务器yarn serve

Vue

  • Vue是一个JavaScript渐进式框架

image-20240502131007181

  • Vue学习方式
    • 传统开发模式:基于html文件开发Vue
    • 工程开发方式:在webpack环境中开发Vue

vue安装

  • 全局安装@vue/cli模块包yarn global add @vue/cli
  • @vue/cli是Vue官方提供的一个全局模块包,此包用于创建脚手架项目
  • vue -V查看是否安装成功
  • VSCode安装插件Vetur

Vue创建项目

  • vue create vuecli-demo项目名不能有大写字母、中文、特殊符号

    image-20240502133129694

image-20240502133836824

  • main.js项目打包主入口
  • App.vueVue页面主入口
  • index.html浏览器运行的文件
  • App.vue---->main,js---->index.html

vue自定义配置

项目中没有 webpack.config.js文件,因为Vue脚手架项目用的vue.config.js

  • 修改端口
module.exports = {
  devServer:{
    port:3000,//修改端口
    open:true//浏览器自动打开
  }
}

eslint

一种代码检查工具,违反规定就报错

module.exports = {
  devServer:{
    port:3000,//修改端口
    open:true//浏览器自动打开
  },
  lintOnSave:false//关闭eslint检查
}

单Vue文件开发

  • Vue推荐采用.vue文件来开发项目
  • template只能有一个根标签
  • js独立作用域互不影响
  • style配合scoped属性,保证样式只针对当前template内标签生效
  • Vetur插件使用<vue>快速创建Vue文件模板

Vue语法

插值表达式
  • 标签中,直接插入vue数据变量
  • {{表达式}}
<template>
  <div>
    <h1>{{ msg }}</h1>
    <h2>{{ obj.name }}</h2>
    <h3>{{ obj.age > 18 ? "成年":"未成年" }}</h3>
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world",
      obj: {
        name: "张三",
        age: 5
      }
    }
  }
}
</script>

<style></style>
MVVM设计模式
  • Mode 模型

  • View 视图

  • VM 视图模型双向关联

  • 减少DOM操作,提高效率

image-20240502143007660

指令
给标签属性设置Vue变量的值
  • 语法
    • v-bind:属性名="vue变量"
    • 简写:属性名="vue变量"

图片需要导入(import),才能使用,直接引用路径不生效

给标签绑定事件
  • 语法
    • v-on:事件名="要执行的少量代码"
    • v-on:事件名="methods中的函数名"
    • v-on:事件名="methods中的函数名(实参)"
    • 简写@事件名="方法"

vue事件处理函数中,拿到事件对象

  • 语法:

    • 函数无传参,通过形参直接接收
    • 函数有传参,通过$event指代事件对象给事件处理函数
    <template>
      <div>
        <a @click="one" href="https://www.baidu.com/">不跳转百度</a><hr/>
        <a @click="two(10, $event)" href="https://www.baidu.com/">不跳转百度</a>
      </div>
    </template>
    
    <script>
    export default {
      methods: {
        //事件触发,不传值,可以直接获取事件对象
        one(e) {
          e.preventDefault()
        },
        //事件触发,传值,使用 $event 传递事件对象
        two(num, e) {
          e.preventDefault()
        }
      }
    }
    </script>
    
    <style></style>>
    

给事件带来更强大的功能

https://cn.vuejs.org/guide/essentials/event-handling.html#event-modifiers

  • @事件名.修饰符="函数"
  • 修饰符列表,修饰符可以链式使用
    • .stop阻止事件冒泡,父级的时间不受影响
    • .prevent阻止默认行为
    • .once程序运行期间,只触发一次事件处理函数

给键盘事件,添加修饰符,增强能力

https://cn.vuejs.org/guide/essentials/event-handling.html#key-modifiers

  • @keyup.enter监测回车按键
  • @keyup.esc监测取消按键
获取表单的值

value属性和Vue数据变量,双向绑定

  • v-model="Vue数据变量"
  • 数据双向绑定,变量变化–>视图自动同步,视图变化–>变量自动同步
  • 下拉框,v-model要绑定到select标签上
  • 复选框,v-model的变量值
    • 非数组,关联的是复选框的checked属性,是否被选中
    • 数组,关联的是复选框的value属性
  • v-model.修饰符="vue数据变量"
    • .number以parseFloat转成数字类型
    • .trim去除首尾空白字符
    • .lazy在change是触发而非input时,失去焦点并且内容改变时在同步数据
更新DOM对象的innerText/innerHTML
  • v-text="vue数据变量"普通字符串原样解析
  • v-html="vue数据变量"当成html解析
  • 并且会覆盖{{}}插值表达式
标签隐藏,出现
  • v-show="vue数据变量"用的是display:none隐藏,适用于频繁切换
  • v-if="vue数据变量"直接在DOM数上移除,可以配合v-else-if v-else一起用
v-for

列表渲染,所在标签结构,按照数据数量,循环生成

  • 语法

    • v-for="(值变量,索引变量) in 目标结构" :key=""
    • v-for="值变量名 in 目标结构"
    • v-for="(value,key) in 对象"
    • v-for="变量名 in 固定数字"
  • v-for放在要循环的标签上

  • 目标结构:数组、对象、数字

目标结构变化,触发v-for更新监测

image-20240503123858974

DOM
  • 真实DOM

image-20240503124022599

  • 虚拟DOM

虚拟DOM本质是一个JS对象,保存DOM关键信息

虚拟DOM提高更新的性能,不频繁操作真实DOM,在内存中找到变化的部分,在更新真实DOM

image-20240503124305376

image-20240503124527235

  • diff算法

image-20240503124857136

image-20240503124916837

  • v-for key对更新的影响

image-20240503125548801

image-20240503125803717

image-20240503130235480

动态class

v-bind给标签class设置动态的值

  • :class="{类名:布尔值}"布尔值为true时,类名才生效
动态style

给标签动态设置style的值

  • :style="{css属性名:值}"
计算属性computed

一个变量的值,依赖另外一些数据计算而来的结果

  • computed:{ "计算属性名"(){return "值"}}
  • 计算属性也是vue数据变量,所以不要和data里重名,用法和data相同
  • 计算属性的优势:计算属性对应函数执行后,会把return值缓存起来,依赖项不变,多次调用都是从缓存取值;依赖项变化,函数会自动重新执行并缓存新的值
<template>
  <div>
    <p>sum:{{sum}}</p>
  </div>
</template>

<script>
export default {
data(){
  return{
    a:5,
    b:10
  }
},
computed:{
    //计算属性也是vue数据变量,所以不要和data里重名,用法和data相同
  sum(){
    return this.a+this.b;
  }
}
}
</script>

<style>

</style>
  • 计算属性完整写法
<template>
  <div>
    <input type="text" v-model="val">
  </div>
</template>

<script>
export default {
  computed: {
    // 属性名
    val: {
      // 设置值,触发set
      set(parm) {
        console.log(parm)
      },
      // 使用值,触发get
      get() {
        return "30";
      }

    }
  }
}
</script>

<style></style>
侦听器watch

可以侦听data、computed属性值的改变

watch:{
	"被侦听的属性名"(newVal,oldVal){

	}
}
<template>
  <div>
    <input type="text" v-model="name">
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: ""
    }
  },
  //侦听器
  watch: {
    // name 要侦听的属性
    name(newName, oldName) {
      console.log(oldName, newName)
    }
  }

}
</script>

<style></style>

image-20240503165111027

<template>
  <div>
    <input type="text" v-model="user.name">
    <input type="text" v-model="user.age">
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: "",
        age: 0
      }
    }
  },
  //侦听器
  watch: {
      // name 要侦听的属性
      user: {
        handler(newVal, oldVal) {
          console.log(oldVal, newVal)
        },
        deep: true,//深度侦听,侦听对象内部的变化
        immediate: true//在侦听开始之后立即调用
      }
  }
}
</script>

<style></style>

组件

  • 可复用的Vue实例,封装标签,样式和JS代码
  • 一个页面,可以拆分成一个个组件,一个组件就是一个整体,每个组件可以有自己独立的结构样式和行为
基础使用

每个组件都是一个独立的个体,代码里体现为一个独立的.vue文件

  • 创建组件,封装要复用的标签、样式、JS代码

  • 注册组件

    • 全局注册:main.js
    import { createApp } from 'vue'
    import App from './App.vue'
    
    const app = createApp(App);
    // 引入组件
    import demo1 from "./components/demo1.vue";
    // 全局注册(组件名 : 组件对象)
    app.component("pannel",demo1)
    app.mount('#app')
    
    
    • 局部注册
    <template>
      <div>
        <pannel2/>
      </div>
    </template>
    
    <script>
    // 引入组件
    import demo1 from "./components/demo1.vue";
    export default {
      // 局部注册
      components:{
        // 组件名 : 组件对象
        "pannel2":demo1
      }
    }
    </script>
    
    <style></style>
    
    • 注册后,和标签一样使用
  • Vue组件内样式,只针对当前组件内标签生效如何做

    • 在 style上添加 scoped <style scoped></style>
    • scoped 会给所有标签添加 data-v-hash 值属性,带属性选择
组件通信
  • 父传子props
    • 子组件,props定义变量
    • 父组件,对子组件变量当做属性赋值
    • 单向数据流
      • 从父到子的数据流向,叫做单向数据流
      • Vue规定props里的变量,本身是只读的
      • 子组件修改,不通知父级,会造成数据不一致
<template>
  <div>
    <!-- 子组件 props 变量接收 -->
    <!-- 父组件,传值进去-->
    <child title="资本论" auth="马克思" price="100"></child>
    <child title="论语" auth="孔子" price="100"></child>
  </div>
</template>

<script>
// 引入组件
import child from "./components/child.vue";
export default {
  // 局部注册
  components:{
    // 组件名,组件对象 同名可简写
    child
  }
}
</script>

<style scoped></style>
<template>
  <div>
    <p>{{ title }}</p>
    <p>{{ price }}</p>
    <p>{{ auth }}</p>
    <hr>
  </div>
</template>

<script>
export default {
  props: ['title', 'price', 'auth']
}
</script>

<style></style>
  • 子传父(自定义事件)
    • 父组件内,在子标签上绑定自定义事件和事件处理函数
      • @自定义事件名="父methods里的函数名"
    • 子组件中,触发事件,在对应事件处理函数中,触发父组件绑定的自定义函数
      • this.$emit('事件名',参数)
<template>
  <div>
    <p>{{ title }}</p>
    <p>{{ price }}</p>
    <p>{{ auth }}</p>
    <button @click="subFn">增加价格1元</button>
    <hr>
  </div>
</template>

<script>
export default {
  props: ['title', 'price', 'auth'],
  methods:{
    subFn(){
      //.$emit('事件名',参数)触发指定事件
      this.$emit('subPrice',this.title,1)
    }
  }
}
</script>

<style></style>
<template>
  <div>
    <!-- subPrice 父组件自定义事件,绑定到子标签上 -->
    <child v-for="(obj, index) in arr" :key="index" :auth="obj.auth" :title="obj.title" :price="obj.price"
      @subPrice="fn" />
  </div>
</template>

<script>
// 引入组件
import child from "./components/child.vue";
export default {
  // 局部注册
  components: {
    // 组件名,组件对象 同名可简写
    child
  },
  data() {
    return {
      arr: [
        { title: "资本论", auth: "马克思", price: 100 },
        { title: "论语", auth: "孔子", price: 100 }
      ]
    }
  },
  methods: {
    // 事件要触发的函数
    fn(title, price) {
      console.log(title,price)
      let index = this.arr.findIndex(x => x.title === title);
      this.arr[index].price += price
    }
  }
}
</script>

<style scoped></style>
  • 跨组件通信 EventBus
生命周期

vue对象从创建到销毁的过程

钩子函数

框架内置函数,随着组件的生命周期阶段,自动执行

阶段 阶段之前执行的方法 阶段之后执行的方法
初始化 beforeCreate created
挂载 beforeMount mounted
更新 beforeUpdate updated
销毁 beforeDestroy destroyed
  • 初始化
    • 执行beforeCreatecreated两个函数
    • created函数触发能获取data,不能获取真实DOM

image-20240503194622883

  • 挂载

image-20240503195626890

  • 更新

image-20240503195817314

  • 销毁
    • 移除一些占用的全局资源,如计时器、定时器、全局事件

image-20240503200215858

组件属性
$refs 获取组件对象
  • 通过id或者 ref 属性获取原生DOM标签
  • 给组件起别名 ref="refStr" ,通过this.$refs.refStr获取组件对象,可以调用组件内一切
<template>
  <div>
    <h1 ref="myH1" id="h">ref/id获取原生DOM</h1>
  </div>
</template>

<script>

export default {
  mounted(){
    console.log(document.getElementById("h"))
    console.log(this.$refs.myH1)
  }
}
</script>

<style>

</style>
$nextTick 等DOM异步更新后,触发函数

Vue更新DOM是异步的

image-20240504103035289

this.$nextTick(函数)等DOM异步更新后触发方法中的函数

image-20240504103209108

组件 name 属性

image-20240504113953966

动态组件
  • 多个组件使用同一个挂载点,并动态切换
  • vue内置component组件,配合is属性(组件名称)

image-20240504123130046

组件缓存
  • 频繁的切换会导致组件频繁创建和销毁,性能不高
  • vue 内置keep-alive组件包起来要频繁切换的组件

image-20240504123917591

  • 组件的激活和非激活,生命周期函数

    • activated激活时触发
    • deactivated失去激活状态触发

    image-20240504124153383

组件插槽

组件里面数据不确定,标签不确定,通过slot标签,让组件内接收不同的标签结构显示

  • 给组件插入什么标签,组件就显示什么标签

  • 使用

    • 组件内用<slot></slot>占位
    • 使用组件时,组件夹着的地方,传入标签替换slot
    • image-20240504124930659
  • 插槽默认内容

    • <slot>内放置内容,作为默认内容
    • 不给组件传标签,slot内容原地显示
    • 给组件内传标签,则slot整体被替换掉
    • image-20240504125524080
  • 作用域插槽

    • 用途:使用插槽时,想使用子组件内变量

    • 使用方法

      • 子组件,在slot上绑定属性:row="变量"

      • image-20240504125919575

      • <template>
          <div>
            <slot :row="defaultObj">{{ defaultObj.name }}</slot>
          </div>
        </template>
        
        <script>
        export default {
          // 作用域插槽
          // 1、 slot标签,自定义属性和内变量关联
          // 2、使用组件,template 配合 v-slot="变量名"
          // 这个变量名会收集slot身上属性和值形成对象
          data() {
            return {
              defaultObj: {
                name: "张飒",
                age: 20
              }
            }
          }
        }
        </script>
        
        <style></style>
        
      • 使用组件,传入自定义标签,用templatev-slot="自定义变量名"

      • image-20240504130024101

      • 这个变量名收