vue 2&3 笔记

Date: 2023-03-12 17:28:46
视频链接:vuejs从入门到精通
ps:我第一遍笔记不太满意,重写一遍 😗
练习项目地址

前置知识

  • HTML5
  • CSS3
  • JS(ES6及以上)

JS 是最重要的。直接关系到你是否真正理解学透,虽然开发不用撸源代码,但更懂一些,对于排除错误极有益处。

不建议直接脚手架学习项目,我看第一遍的时候,是直接找脚手架安装了,导致我对 vue 的一些基本知识就不知道,就像创建 vue 实例的函数式方法,一直没看太懂,直到第二遍从头看,我才知道可以传个配置对象。再实现vue实例对象

这篇课程学习的版本为 vue@2.7 之前的版本,vue@2 将在 2023/12/31 后不再维护,建议学习 vue@3 版本

Vue 2 的长期技术支持 (LTS)

vue2

P1 课程介绍

讲的挺好的,b站最好的 vue 教程,值得一看

P2~4 Vue简介

vue官网,只不过现在更新到 vue3 了,vue2 要在文档里面找

Vue官方使用指

不会在官网里查就行

搭建 Vue 开发环境

vue.js      \\ 开发版本
vue.min.js  \\ 生产版本,已经压缩

在 chrome 商店搜索 vue 插件安装即可
关闭开发版本提示

开始学习时,先不用脚手架接触框架 🌠

P5~10 vue 核心

Hello 小案例 ---P5🎈

// html代码
<div id="root">
  <h1>{{name}}</h1>
</div>
//创建Vue实例对象,里面传个对象
new Vue({
  el: "#root", //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
  data: {
    //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
    name: "hello,world!",
  },
});

vue 实例对象 挂载在DOM节点上


上次更新: 2023-03-31 19:55:14


分析 Hello 小案例 ---P6

JS表达式 和 JS语句 的区别? 表达式能接到 val,语句不能

  • Vue 创建实例对象后,才能工作,里面需要传一个配置对象
  • DOM 模板语法符合HTML 规范,但增加了一些特殊语法
  • DOM 模板里的代码被称为 Vue模板
  • 容器和vue实例要一一对应
  • {{xxx}} 里的 xxx 为 js表达式,xxxthisvue 实例对象
  • 一旦 data 改变,模板中用到的地方也会自动更新

模板语法 ---P7

  • 插值语法
    • 功能: 用于解析标签体内容。
    • 写法: {{xxx}}xxx是js表达式,且可以直接读取到data中的所有属性。
    • 注:模板语法的 this 为 vm,并未浏览器对象BOM
  • 指令语法
    • 功能: 用于解析标签(包括:标签属性、标签体内- 容、绑定事件.....)。
    • 举例: v-bind:href="xxx" 或 简写为 :href="xxx",xxx 同样要写 js表达式,且可以直接读取到data中的所有属性。
    • 备注: Vue中有很多的指令,且形式都是:v-?,此处我们只是拿v-bind举个例子。
<div id="root">
  <h3>hello,{{name}}</h3>
  <a :href="profile.href" :fun="profile.note.toUpperCase()">点我跳转{{profile.xxx}}</a>
</div>

new Vue({
  el: "#root",
  data: {
    name: "gavin",
    profile: {
      href: "https://www.cnblogs.com/isgavin/",
      xxx: "技术博客",
      note:"justNote"
    }
  },
});

数据绑定 ---P8

单向数据绑定,data => DOM
v-bind:href ="xxx" 或简写为 :href xxx 会被作为js表达式解析

双向数据绑定 data <=> DOM
v-mode:value="xxx" 或简写为 v-model="xxx"

el 与 data 的两种语法 ---P9

const v= new Vue({
  // el:'#root' el第一种写法
})
v.$mount('#root') //el第二种写法

new Vue({
  // data:{
  //   name: 'AAA' //data 第一种写法
  // }
  data: function(){ //data 第二种写法
    return {
      name: 'AAA'
    }
  }
}).$mount('#root')

el函数方法 的写法能灵活一些,都一样,就赋值挂载而已。

为什么不能用 data 的第一种写法?

组件化后,不同组件共用了同一个内存地址,componentA 修改的内容,同样对 componentB 产生了影响

如果我们采用函数的形式,则不会出现这种情况(函数返回的对象内存地址并不相同)

理解 MVVM ---P10

MVVM 模型

M:模型(Model):对应 data 中的数据
V:视图(View) :DOM 模板
VM:视图模型(ViewModel) : Vue 实例对象


P11 Object.defintProperty

vue2 实现响应式数据的方式

P12 理解数据代理

P13 Vue中的数据代理

有时间再看


P14~17 事件处理

事件的基本使用 P14

  1. 使用v-on:xxx@xxx 绑定事件,其中xxx是事件名;
  2. 事件的回调需要配置在methods对象中,最终会在vm上;
  3. methods 中配置的函数,不要用箭头函数!否则this就不是 vm 了;
  4. methods 中配置的函数,都是被 Vue 所管理的函数,this的指向是 vm 或 vc
  5. @click="demo"@click="demo($event)" 效果一致,但后者可以传参并可以将 event对象 带过去进行处理;

上次更新: 2023-04-01 12:00:37


事件修饰符 P15

Vue中的事件修饰符:@click.事件修饰符="handleClick"

  1. prevent:阻止默认事件(常用);event.preventDefault()
  2. stop:阻止事件冒泡(常用);event.stopPropagation()
  3. once:事件只触发一次(常用);
  4. capture:使用事件的捕获模式;
  5. self:只有event.target是当前操作的元素时才触发事件;也可以阻止冒泡
  6. passive事件的默认行为立即执行,无需等待事件回调执行完毕;

@scroll 滚动条滚动,@wheel 鼠标滚动移动,有必要复习一下浏览器事件

什么是事件冒泡?

<ul @click="handleClick">
  <li @click="handleClick">AAA</li>
</ul>

点击子元素,同样会触发父级元素的事件方法。被称为事件冒泡

按键修饰符 P16

  1. Vue中常用的按键别名:@keyup.enter="handleKeycode"

    • 回车 => enter
    • 删除 => delete (捕获“删除”和“退格”键)
    • 退出 => esc
    • 空格 => space
    • 换行 => tab (特殊,必须配合keydown去使用)
    • 上 => up
    • 下 => down
    • 左 => left
    • 右 => right
  2. Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
    按空格 @keyup.caps-lock="handleCick"

  3. 系统修饰键(用法特殊):ctrl、alt、shift、meta

    • (1) 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
    • (2) 配合keydown使用:正常触发事件。@keydown.ctrl="handleKeycode"
  4. 也可以使用keyCode去指定具体的按键(不推荐)(因为不同键盘的编码不一致,web 标准可能废弃)

  5. Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名(没啥区别,常用够用)

事件总结 P17

  • 事件修饰符可以连着写 @click.once.prevent="handleClick"
  • 系统修饰符也可以连着写
    @keyup.ctrl.y="handleClick" 只有ctrl+y 同时按可以触发事件

P18~25 计算属性 与 监视属性

姓名案例 P18🎈

引出计算属性

计算属性 computed P19

使用场景 要显示的数据不存在,要通过依赖 data 计算得来。

如何使用

computed 对象中定义计算属性。在页面中使用{{方法名}}来显示计算的结果

data:{        // vm._data
  firstName:'张',
  lastName:'三'
},
computed:{    // 使用时用插值语法 {{fullName}} 即可
  fullName:{
    // vue 管理的函数不能使用箭头函数
    get(){ // 何时调用,1.初次读取时,2. 所依赖的数据发生变化时
      return this.firstName+'-'+this.lastName //this 为 vm
    }
    // 当 fullName 被修改时触发
    set(){ 
      const arr =value.split('-')
      this.firstName=arr[0]
      this.lastName=arr[1]
    }
  }
}

计算属性的数据会被复用,效率更高

计算属性简写方式 P20

只适用 get() 时计算属性可简写

computed:{
  fullName(){
    return this.firstName+'-'+this.lastName
  }
}

天气案例 P21🎈

引出监视属性的使用

监视属性 P22

使用场景

datacomputed 发生变化时,要进行一些操作。
来监视指定的属性计算属性,属性变化时, 回调函数自动调用, 在函数内部进行计算

如何使用

通过watch 配置

data:{
  isHot:true,
},
watch:{
  isHot:{
    immediate: true, //初始化时就开始监听
    handler(newValue,oldValue){ //数据改变 handler 开始调用
      console.log('info被修改了',newValue,oldValue)
    }
  }
}

通过 vm 对象$watch()

vm.$watch('isHot':{ //一样,就是外层结构改一下
  immediate: true, //初始化时就开始监听
  handler(newValue,oldValue){ //数据改变 handler 开始调用
    console.log('info被修改了',newValue,oldValue)
  }
})

深度监视 P23

根据数据结构和需求,选择是否添加深度监视

data:{
  numbers:{
    a:1,
    b:2
  }
},
watch:{
  numbers:{
    deep:true, //深度监视 numbers 和其子属性 改变
    handler(newValue,oldValue){
      console.log('info被修改了',newValue,oldValue)
    }
  }
}

监视的简写形式 P24

配置项中只使用 handler 时使用,开发时能用简写用简写

// 简写形式
watch:{
  isHot(newValue,oldValue){
    console.log('info被修改了',newValue,oldValue)
  }
}
vm.$watch('isHot',function(newValue,oldValue){ //不能写成箭头函数,会造成 this 指向问题
  console.log('info被修改了',newValue,oldValue)
}
)

watch 对比 computed P25

watch 对比 computed 的区别

watch:{
  isHot(val){
    setTimeout((val)=>{ //this 指向是什么?
      console.log('info被修改了',val)
    },1000)
  }
}

两者的使用场景非常相近,computed 能做到的 watch 也能做到,但 computed 性能更高,所以优先使用 computed ,

computed 不能开启异步任务,因为其依靠 return 返回值

P26-27. class 与 style 绑定

应用场景: 实现动态样式效果

不管怎么写,原理就是vue的单向数据绑定,根据业务需求修改

实现 class 绑定

data() {
  return {
    xxx: "b2",
  };
},
// HTML
<button class="basic" :class="xxx" @click="handleClass">切换 class</button>

元素上添加 :class='xxx'
data 上为

  • 字符串: xxx:'classA'
  • 对象: xxx:{classA:isA, classB: isB}
  • 数组: xxx:['classA','classB']

实现 style 绑定

  data() {
    return {
      styleObj: {
        color: "blue",
        fontSize: "50px",
        backgroundColor: "yellow",
      }
    };
  },
// HTML
<div :style="styleObj">style 修改</div>

P28~32 条件渲染和列表渲染

条件渲染 ---P28

// 这一堆不能打断
<h3 v-if="n===1">AAA</h3>
<h3 v-else-if="n===2">BBB</h3>
<h3 v-else-if="n===3">CCC</h3>
<h3 v-else>noneValue</h3>

<template v-if="val"></template> 只能配合 v-if 使用

面试题:比较 v-ifv-show的区别?

面试题链接,我写的还行


上次更新: 2023-04-02 11:02:32


列表渲染 ---P29

v-for 指令:

  1. 用于展示列表数据
  2. 语法:v-for="(item, index) in xxx" :key="yyy"
  3. 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

key 作用和原理 ---P30

key 是 diff 算法标识符,用于提高DOM效率

列表过滤 ---P31

对要显示的数据进行特定格式化后再显示
注意: 并没有改变原本的数据, 是产生新的对应的数据

列表排序 ---P32

列表排序功能

33~38 Vue监视数据的原理

更新的一个问题 ---P33

更新后发现数据没有更新,原因是 difineProperty 的特性

P34 Vue监视数据的原理-对象

P35 Vue.set() 方法

P36 Vue监视数据的原理-数组

P37 vue 监视数据-总结

P38 收集表单数据 🎈

写一份原生的,写一份 element-ui 的。

收集表单数据:

  • <input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
  • <input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
  • <input type="checkbox"/>
    1. 没有配置 input 的 value 属性,那么收集的就是 checked(勾选 or 未勾选,是布尔值)
    2. 配置 input 的 value 属性:
      (1) v-model的初始值是非数组,那么收集的就是 checked(勾选 or 未勾选,是布尔值)
      (2) v-model 的初始值是数组,那么收集的的就是 value 组成的数组
  • 备注:v-model 的三个修饰符:
    • lazy:失去焦点再收集数据
    • number:输入字符串转为有效的数字
    • trim:输入首尾空格过滤

v-module 配合不同的标签元素

P39 过滤器

vue@3 中已经移除过滤器

P40~47 vue 指令系统

vue 的内置指令和自定义指令

v-text 指令 ---P40

更新元素的 文本内容,不常用

v-html 指令 ---P41

介绍 cookie

cookie 是一种本地存储技术,实现持久化登录的一种方式。

工作原理:服务器发送到用户浏览器并保存在本地的一小段文本信息,每次浏览器向同一服务器再发送请求时,都会携带这个 cookie 信息。

有可能被盗取,添加 httponly 属性,防止 XSS 攻击

v-html指令:

作用:向指定节点中渲染包含html结构的内容。

与插值语法的区别:
(1).v-html 会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html 可以识别 html结构。 <div v-html="HtmlData"></div>

严重注意:v-html 有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

v-cloak 指令 ---P42

解决 js 阻塞渲染,防止闪现, 与 css 配合使用:

  • 先在 元素上设置 <h3 v-cloak>{{data}}</h3>
  • 元素标签设置 [v-cloak]{display: none}

当 vue 加载完毕后,会自动移除该属性。

v-once 指令 ---P43

v-once 所在节点在初次动态渲染后,就视为静态内容了 <h3 v-once>{{data}}</h3>

以后数据的改变不会引起 v-once所在结构 的更新,可以用于优化性能。data 变化不会在页面上显示了

v-pre 指令 ---P44

跳过其所在节点的编译过程,可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译速度

自定义指令-函数式 ---P45

操作 DOM 的代码 封装成一个函数指令

注册自定义指令

export default {
  name: 'app',
  directives: {
    upcase(el, binding) {
      el.innerHTML = binding.value.toupperCase()
    }
  }
}
  • el 为真实的 DOM 元素,
  • binding 为当前DOM的配置对象

使用指令 v-upcase='xxx

执行时机

指令与元素成功绑定时 bind,页面模板重新解析时再次执行 update

自定义指令-对象式 ---P46

export default {
  name: 'app',
  directives: {
    upcase: {
      bind (el, binding) {
        el.innerHTML = binding.value.toupperCase()
      },
      inserted (el, binding) {
        el.focus()
      },
      update (el, binding) {
        el.innerHTML = binding.value.toupperCase()
      }
    }
  }
}

自定义指令-总结 ---P47

  • 书写的时候,如果指令名较长,可以用 - 连接单词。
  • 指令函数中的 this 为 BOM 对象
  • 定义全局指令:所有组件都可使用
    Vue.directive(指令名,配置对象)Vue.directive(指令名,回调函数),使用插件安装全局指令

P48~52 Vue 生命周期

vue 生命周期钩子函数

> 挂载流程 初始化显示

  • beforeCreate() 数据监测、数据代理创建前
  • created() 可以通过 vm 访问到 data 中的数据、methods中配置的方法。
  • beforeMount() 虚拟DOM还在内存中,没有变成真实 DOM
  • mounted() Vue完成模板解析,初始 DOM 已生成

> 更新流程
更新状态: this.xxx = value

  • beforeUpdate() 数据是新的,页面是旧的
  • updated() 数据是新的,页面也是新的

> 销毁流程
销毁 vue 实例: vm.$destory()

  • beforeDestory() 对 data 做的所有操作都不会触发更新了
  • destoryed()

在各个生命周期一般要做的事情

created() 发送 Api 请求
mounted(): 启动定时器等异步任务、绑定自定义事件、订阅消息、发送 Api 请求等
beforeDestory(): 做收尾工作, 如: 清除定时器、清楚订阅、解绑自定义事件等

面试题:在created() 和在 mounted() 里写接口请求有什么区别?

在 mounted() 里写接口请求,因为DOM已经生成,所以可能会造成闪屏,用户体验不佳。

P53~60 关于单文件组件

对组件的理解 ---P53

一种新的网页开发方式,将相关的 HTML,js,css 部分放在一起组成的单文件组件。

Vue中使用组件的三大步骤:

>一、 定义组件(创建组件)

  • 使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
  • 区别如下:
    • el不要写,为什么?
      最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
    • data必须写成函数,为什么?
      避免组件被复用时,数据存在引用关系。
    • 备注:使用 template 可以配置组件结构。

>二、 注册组件

  • 局部注册:靠new Vue的时候传入components选项
  • 全局注册:靠Vue.component('组件名',组件)

>三、 使用组件(写组件标签) <school></school>

非单文件组件 ---P54

传统 HTML 网页

组件的几个注意点 ---P55

  1. 关于组件名:

    • 一个单词组成:首字母大写
      第一种写法(首字母小写):school
      第二种写法(首字母大写):School
    • 多个单词组成:大驼峰命名
      第一种写法(kebab-case命名):my-school
      第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
    • 备注:
      (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。所以首字母大写
      (2).可以使用 name配置项 指定组件在开发者工具中呈现的名字。
  2. 关于组件标签:
    第一种写法:<school></school>
    第二种写法:<school/>
    备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

  3. 一个简写方式:
    const school = Vue.extend(options) 可简写为:const school = options

组件的嵌套 ---P56

引入其他组件

  • import Home from '../components/Home.vue'
  • 在配置对象里注册
export default {
  component: {Home}
}
  • 在 template 中使用 <Home/>

VueComponent 构造函数 ---P57

组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成

Vue解析到自定义组件标签Demo/>时,会帮我们创建组件的实例对象,
即Vue帮我们执行的:new VueComponent(options)

特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent

Vue实例与组件实例 ---P58

关于this指向:

  • 组件配置中:vc
    data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
  • new Vue(options)配置中:vm
    data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

VueComponent 的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

一个重要的内置关系 P59

一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype

为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

vm 与 vc 关系图

P60 单文件组件

一个.vue 文件的组成(3 个部分)

<template>  // 页面模板
</template>
<script>    // 模块对象
export default {
  data() {
    return {}
  }, 
  methods: {}, 
  computed: {}, 
  components: {}
}
</script>
<style>     // 样式定义
</style>

P61~64 Vue 脚手架

创建Vue脚手架 ---P61

使用 vue 脚手架工具 Vue CLI

Vue 脚手架隐藏了所有 webpack 相关的配置,若想查看具体的 webpakc 配置,
请执行:vue inspect > output.js,之所以隐藏,就是不想让你动里面的东西,修改在vue.config.js中设置就可以了

Date:2023-04-06 11:14:10
以上已过时,现在的脚手架工具为 vite

脚手架文件结构 ---P62

├── node_modules
├── public (文件不会被脚手架压缩处理)
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源,(文件会被脚手架压缩处理)
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ │── main.js: 入口文件
├── .gitignore: git 版本管制忽略的配置
├── babel.config.js: babel 的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件

关于不同版本的Vue ---P63

  1. vue.jsvue.runtime.xxx.js 的区别:
    vue.js 是完整版的 Vue,包含:核心功能 + 模板解析器。
    vue.runtime.xxx.js 是运行版的 Vue,只包含:核心功能;没有模板解析器。
  2. 因为 vue.runtime.xxx.js 没有模板解析器,所以不能使用 template 这个配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。

修改默认配置 ---P64

P65 ref 🎆

使用场景:用于给节点打标识

<h3 v-text="text" ref="title"></h3>
读取 this.$refs.xxxxxx

跟 react 的 string ref 写法一样。

也可以 写在组件标签上拿到组件的实例对象

P66 props 属性 🎆

用于父组件 => 子组件传递数据

传递数据

<Demo name="xxx" :age="18+1"/>

接收数据

在子组件中

props: ["name", "age", "sex"],
// 限制类型
props:{
  name:String,
  age:Number,
  sex:String
}
// 限制类型和其他配置
props: {
  name: {
    type: String,
    required: true,
  },
  age: {
    type: Number,
  },
  sex: {
    type: String,
    default: "男",
  },
},

注意

props只读的,Vue 底层会监测你对 props 的修改,如果进行了修改,就会发出警告。
若业务需求确实需要修改,那么请复制 props 的内容到 data 中一份,然后去修改 data 中的数据

P67~69 可复用性 & 组合

mixin 混入 ---P67

使用场景: 复用 vm 里所写的配置

如何使用

  • in src/ create mixin.js 文件

  • mixin.js 中写通用配置

    export const toMix = {
      methods:{
        show(){
          alert("这是混入内容")
        }
      }
    }
    export const AAA = {
      methods:{
        show(){
          alert("这是AAA")
        }
      }
    }
    
  • 在目标组件里 局部混合

    import {toMix,AAA} from "@/mixin.js"
    export default {
      mixins: [toMix,AAA]
    }
    

    全局混入 会污染所有 vm/vc
    main.js

    import {toMix,AAA} from "@/mixin.js"
    Vue.use(toMix)
    Vue.use(AAA)
    

注:发生冲突以组件为主,生命周期钩子全部生效

插件 ---P68

使用场景

用于增强 Vue 功能,里面可以写 过滤器、全局指令、混入等等,无需一个个在 main.js 中引入使用。一次引入即可解决

其本质:包含 install 方法的一个对象,install 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据。

如何使用

  • 定义插件,create plugins.js
  • plugins.js 写内容
export default{
install = function (Vue, options) {
    // 1. 添加全局过滤器
    Vue.filter(....)
    // 2. 添加全局指令
    Vue.directive(....)
    // 3. 配置全局混入(合)
    Vue.mixin(....)
    // 4. 原型添加实例方法
    Vue.prototype.$myMethod = function () {...}
    Vue.prototype.$myProperty = xxxx
  }
}
  • main.js中,引入使用

    import plugins from './plugins' 
    Vue.use(plugins)                
    

scoped 样式 ---P69

使用场景:让样式在局部生效,防止冲突。
写法:<style scoped>
使用插件:Vue.use()

P70~77 组件化编码开发流程(通用思路)

  1. 实现静态组件:抽取组件,使用组件实现静态页面效果
  2. 展示动态数据:
    数据的类型、名称是什么
    数据保存在哪个组件?
    • 一个组件在用:放在组件自身即可。
    • 父子组件在用:放在他们共同的父组件上(状态提升)
  3. 交互——从绑定事件监听开始,处理交互逻辑

P78 webStorage

  • 存储内容大小一般支持 5MB 左右(不同浏览器可能还不一样)
  • 浏览器端通过 Window.sessionStorageWindow.localStorage 属性来实现本地存储机制。

相关 API

  1. xxxxxStorage.setItem('key', 'value'); 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。
  2. xxxxxStorage.getItem('person'); 该方法接受一个键名作为参数,返回键名对应的值。
  3. xxxxxStorage.removeItem('key'); 该方法接受一个键名作为参数,并把该键名从存储中删除。
  4. xxxxxStorage.clear() 该方法会清空存储中的所有数据。

TodoList-实现本地存储 ---P79🎈

P80~82 组件的自定义事件

使用场景: 一种 子组件 ===> 父组件 通信的方式,react 里也有

子组件 ===> 父组件 通信的方式 ---P80

> 一、 向子组件 传一个 props 的方法,然后子组件触发此方法,将数据带到父组件

  • 父组件中 <Demo :getSonData="xxx"
  • 子组件中 接收props后 @click="getSonData(data)"

> 二、 在子组件标签上绑定一个方法,然后在子组件里触发自定义方法,将数据带回来,在组件销毁前解绑

  • 父组件中 <Demo @getSonData="xxx">
  • 子组件中 this.$emit("getSonData", this.data);

> 三、 通过 ref 直接拿到子组件的实例对象

  • 父组件中 <Demo ref="vc"\>
  • 直接拿到子组件的实例对象 this.$refs.vc

> 四、 通过 ref 在生命周期里使用 $on方法钩子 绑定自定义事件

  • 父组件中 <Demo ref="vc">
    然后拿到子组件绑定自定义事件 this.$refs.vc.$on("getSonData", this.xxx);
  • 子组件中 this.$emit("getSonData", this.data);

自定义事件-解绑 ---P81

解绑一个 this.$off('111')
解绑多个 this.$off(['111','222'])
解绑全部 this.$off()

一般在 beforeDestroy() 生命周期钩子里进行解绑

自定义事件-总结 ---P82

在方法四中
this.$refs.vc.$on("getSonData", console.log(this));

谁触发,this 在谁手里,此时 this 为 子组件实例对象

<Demo @click="show"></Demo>
click 此时为自定义事件,将其 + @click.native 变为原生事件

自定义事件-TodoList案例 ---P83🎈

P84~85 全局事件总线

理解 vm 与 vc 的关系 ---P84

Object 对象原型链

实现全局事件总线 ---P85

使用场景: 不相关组件间的通信方式

实现原理

在Vue原型对象上, 挂了一个vue实例对象,俗称套娃

使用方式

先创建事件总线对象,注意时机,在创建前在 vm 上挂载一个 vc

new Vue({
  beforeCreate () { // 尽量早的执行挂载全局事件总线对象的操作
    Vue.prototype.$bus = this //安装全局事件总线,$bus
  },
})

A 组件提供数据:this.$bus.$emit('getData',数据)

B 组件接收数据:

this.$bus.$on('getData',方法(数据))

记得解绑当前组件用到的自定义事件 this.$bus.$off('getData')

全局事件总线-TodoList案例 ---P86🎈

P87 消息订阅与发布-pubsub

官网 Basic use

使用场景: 不相关组件间的通信方式

Vue 不常用,react 经常使用,这种方式的使用和原理与全局事件总线很相似

如何使用

它包含以下操作:

(1) 订阅消息 --对应绑定事件监听
(2) 发布消息 --分发事件
(3) 取消消息订阅 --解绑事件监听

安装包 npm i pubsub-js

main.js 全局引入: import PubSub from 'pubsub-js'

具体使用

// A组件提供数据:
PubSub.publish('getData',数据)

// 接收数据:
token = PubSub.subscribe('geData',function(消息名,data))
PubSub.unsubscribe(token)

vue3 ,不能传对象,还是要用 mitt,也没必要,

全局事件总线-TodoList案例 ---P88🎈

编辑-TodoList案例 ---P89🎈

P90 nextTick

使用场景 当改变数据后,要基于更新后的新 DOM 进行某些操作

要在 nextTick 所指定的回调函数中执行。在下一次 DOM 更新结束后执行其指定的回调

watch: {
  list () {
    this.$nextTick(() => { // 在下一次 DOM 更新结束后执行其指定的回调
    console.log("DOM 更新了")
    })
  }
}

P91~95 Vue 动画

使用场景: 在插入、更新或移除 DOM 元素时,在合适的时候给元素添加样式类名
理解: 操作 css 的 trasition 或 animation,vue 会给目标元素添加/移除特定的 class

过渡与动画 ---P91

<transition name="name" appear> //解析后脱掉了
  <h3>这是动画</h3>
</transition>

appear 为初始化渲染

.name-enter-active{animation:ianime 0.5s linear;}
.name-leave-active{animation:ianime 0.5s linear;}
@keyframes ianime{}

过渡效果 ---P92

元素进入的样式:
1. name-enter:进入的起点
2. name-enter-active:进入过程中
3. name-enter-to:进入的终点

元素离开的样式:
1. name-leave:离开的起点
2. name-leave-active:离开过程中
3. name-leave-to:离开的终点

使用<transition> 包裹要过渡的元素,并配置 name 属性

多个元素过渡 ---P93

在多个元素外增加 <transition-group></transition-group>

若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

集成第三方动画库 ---P94

css动画库,Animate.css

代码示例

  • yarn add animate.css
  • 然后在组件中引入 import "animate.css"
  • 书写代码
<transition 
  appear
  name="animate__animated animate__bounce" 
  enter-active-class="动画名"
> //解析后脱掉了
  <h3>这是动画</h3>
</transition>

总结过渡与动画 ---P95

根据需求进行使用 官方文档

P96~97 配置代理

面试题:如何解决开发环境的跨域问题?

根本原因是浏览器同源策略的限制,实际上请求的接口数据已经收到,只不过被浏览器拦截了,解决方式有很多,主要是挂代理,因为 服务器 \(\Rightarrow\) 服务器没有此限制。
在 vue 项目中,官方脚手架已经内置了解决方案,主要是使用 nodejs开个本地服务器代理进行转发,稍微设置一下即可

vue 项目中常用的 Ajax 库, axios

axios 对 原生hdr请求 进行了一次封装,是我们能够更好的发送请求。

在实际开发过程中,一般会对 axios 进行二次封装,扔到 utils 文件夹里,目的是统一进行请求,响应拦截处理,简化请求发送代码

P98~100 搜索案例🎈

P101 vue-resource

hdr 请求库,官方推荐使用 axios

P102~104 插槽

slot 插槽 ---P102

使用场景: 父组件 => 子组件传递带数据结构不定的标签

插槽内容是在父组件中编译后, 再传递给子组件的。

分类

  1. 默认插槽
  2. 命名插槽
  3. 作用域插槽

使用方式

在父组件中<Demo>父组件向子组件放的结构</Demo>
在子组件中<slot></slot>,为父组件中的结构占位
结构样式父组件和子组件都可以定义

具名插槽 ---P103

如果在父组件中写多个插槽,每个插槽必须命名

子组件中

<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>

父组件中

<Demo title="美食" >
  <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
  <template v-slot:footer>
    <div class="foot">
      <a href="http://www.atguigu.com">经典</a>
    </div>
    <h4>欢迎前来观影</h4>
  </template>
</Demo>

作用域插槽 ---P104

使用场景

数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。

slot 可将数据传递给父组件

如何使用

在子组件中:

<template>
  <div>
    <slot :datas="datas"></slot>
  </div>
</template>
<script>
export default {
  name: "Demo",
  data() {
    return {
      datas: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
    };
  },
};
</script>

在父组件中

<Demo>
  <template scope="scopeData">
    <!-- 生成的是ul列表 -->
    <ul>
      <li v-for="g in scopeData.games" :key="g">{{g}}</li>
    </ul>
  </template>
</Demo>
<Demo>
  <template scope="scopeData">
    <!-- 生成的是ul列表 -->
    <ol>
      <li v-for="g in scopeData.games" :key="g">{{g}}</li>
    </ol>
  </template>
</Demo>

P105~116 Vuex

Vuex 简介 ---P105

 最新版更名为 pinia,我之后会在后面写 pinia 的使用方式,确实 mutation 数据更新,极为没必要

使用场景官方用来解决 无直接关系组件使用通用数据 的方案

// data 数据存储
const state = {
  xxx: initValue
}
// 处理请求,无所谓的,直接写一起也没什么
const actions = {
  zzz({commit,state},data1){
    commit('yyy',{data1})
  }
}
// 直接修改数据 pinia 直接干掉了,大可不必
const mutations={
  yyy (state, {data1}){
    //更新state的某个属性
  }
}
// vuex 里的 计算属性
const getters = {
  mmm(state){
    return state.msg+'!'
  }
}

modules

  1. 包含多个 module
  2. 一个 module 是一个 store 的配置对象
  3. 与一个组件(包含有共享数据)对应

求和案例 普通版🎈 ---P106

Vuex 工作原理图 ---P107

搭建 Vuex 环境 ---P108

  1. 安装 vuex npm i vuex

  2. main.js 中在创建 vm 时传入 store 配置项

//引入store
import store from "./store";
//创建vm
new Vue({
  el: "#app",
  render: (h) => h(App),
  store,
});
  1. 然后创建 src/store/index.js 文件
//引入Vue核心库
import Vue from "vue";
//引入Vuex
import Vuex from "vuex";
//应用Vuex插件
Vue.use(Vuex);

//准备actions对象——响应组件中用户的动作
const actions = {};
//准备mutations对象——修改state中的数据
const mutations = {};
//准备state对象——保存具体的数据
const state = {};

//创建并暴露store
export default new Vuex.Store({
  actions,
  mutations,
  state,
});

求和案例 vuex版🎈 ---P109

Vuex 开发者工具 ---P110

chrome商店vuex插件

getters 配置项 ---P111

概念:当 state 中的数据需要经过加工后再使用时,可以使用 getters 加工。像组件里的computed

store.js中追加getters配置

......
  // in store.index.js file,similar component computed attribute.
const getters = {
  bigSum(state){
  return state.sum * 10
  }
}

//创建并暴露store
export default new Vuex.Store({
  ......
  getters
})

组件中读取修改后的数据:$store.getters.bigSum

四个 map 方法的使用 ---P112-113

mapState 与 mapGetters
mapActions 与 mapMutations

如果此组件里使用vuex api 比较多,可使用这4个方法脱壳,简化书写

  • mapState 方法:映射state中的数据
computed: {
  //借助mapState生成计算属性:sum、school、subject(对象写法)
  ...mapState({sum:'sum',school:'school',subject:'subject'}),

  //借助mapState生成计算属性:sum、school、subject(数组写法)
  ...mapState(['sum','school','subject']),
},
  • mapGetters 方法:用于帮助我们映射getters中的数据为计算属性
computed: {
    //借助mapGetters生成计算属性:bigSum(对象写法)
    ...mapGetters({bigSum:'bigSum'}),

    //借助mapGetters生成计算属性:bigSum(数组写法)
    ...mapGetters(['bigSum'])
},
  • mapActions 方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数
methods:{
    //靠mapActions生成:incrementOdd、incrementWait(对象形式)
    ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

    //靠mapActions生成:incrementOdd、incrementWait(数组形式)
    ...mapActions(['jiaOdd','jiaWait'])
}
  • mapMutations 方法 :用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数
methods:{
    //靠mapActions生成:increment、decrement(对象形式)
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),

    //靠mapMutations生成:JIA、JIAN(对象形式)
    ...mapMutations(['JIA','JIAN']),
}

备注:mapActions 与 mapMutations 使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

多组件共享数据 ---P114

基本使用

初始化数据、配置actions、配置mutations,操作文件store.js

import Vue from "vue";    //引入Vue核心库
import Vuex from "vuex"; //引入Vuex
Vue.use(Vuex);            //引用Vuex,先import后jscode.
const actions = { //响应组件中加的动作
  jia(context, value) {
    // console.log('actions中的jia被调用了',miniStore,value)
    context.commit("JIA", value);
  },
};
const mutations = { //执行加
  JIA(state, value) {
    // console.log('mutations中的JIA被调用了',state,value)
    state.sum += value;
  },
};
//初始化数据
const state = {
  sum: 0,
};
//创建并暴露store
export default new Vuex.Store({
  actions,
  mutations,
  state,
});

组件中读取 vuex 中的数据:$store.state.sum

组件中修改 vuex 中的数据:
$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)

备注:

若没有网络请求或其他业务逻辑,组件中也可以越过 actions,即不写dispatch,直接编写commit

原则:

只要有一些业务逻辑,都放在actions里。mutation 只负责改变值。大可不必,顾客才不在乎厨师怎么做的饭。

vuex 模块化 namespace P115-116

使用场景:大型项目通用数据较多,为了让代码更好维护,让多种数据分类更加明确。

修改store.js

const countAbout = {
  namespaced:true,//开启命名空间
  state:{x:1},
  mutations: { ... },
  actions: { ... },
  getters: {
    bigSum(state){
        return state.sum * 10
    }
  }
}
const personAbout = {
  namespaced:true,//开启命名空间
  state:{ ... },
  mutations: { ... },
  actions: { ... }
}
const store = new Vuex.Store({
  modules: {
    countAbout,
    personAbout
  }
})

开启命名空间后,组件中读取 state 数据:

//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),

开启命名空间后,组件中读取 getters 数据:

//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])

开启命名空间后,组件中调用 dispatch

//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

开启命名空间后,组件中调用 commit

//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

vuex的简化封装(uView框架)

P117~133 Vue 路由管理

🔥🔥🔥 ❗ 学习使用版本为 vue-router@3

2022/2/7 后,vue-router 默认版本为@4,只能在 vue@3 中使用,vue-router@3,只能在 vue@2 中使用

vue-router介绍 ---P117

vue 的一个插件库,专门用来实现SPA的。

路由分类

后端路由:

  • 理解:value 是 function, 用于处理客户端提交的请求。
  • 工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据。

前端路由:

  • 理解:value 是 component,用于展示页面内容。
  • 工作过程:当浏览器的路径改变时, 对应的组件就会显示。

路由基本使用 ---P118

路由的基本使用

  1. 安装 vue-router,命令:yarn add vue-router@3
  2. 引入并应用插件:
  3. main.js 中的vue配置项 可编写 router 配置项
  • 编写 .active,设置激活后样式
    <router-link to="" active-class="active"></router-link>

制定组件呈现位置 <router-view></router-view>


编写使用路由的 3 步

  1. 定义路由组件,在 views 文件夹里定义 xxx.vue 组件,这个文件夹里都是要展现的页面。在页面中实现切换高亮样式
    <router-link active-class="active" to="/about">About</router-link>

  2. 注册路由,在 vueRouter 里统一注册,编写好路径

import Vue from "vue";
import VueRouter from "vue-router"; //引入VueRouter
Vue.use(VueRouter) //安装路由
//创建router实例对象,去管理一组一组的路由规则
const router = new VueRouter({ //将路由对象实例化
  routes: [
    {
      path: "/about",
      component: () => import("../components/About"),
    },
    {
      path: "/home",
      component: () => import("../components/Home"),
    },
  ],
});
export default router; //暴露router
  1. 使用路由,在页面里引入使用。
    指定展示位置<router-view></router-view>

几个注意点 ---P119

  1. 路由组件通常存放在views文件夹,
    一般组件通常存放在components文件夹。
  2. 通过切换,原有的路由组件默认是被销毁掉的,需要的时候再去挂载。
  3. 每个组件 vc都有自己的$route属性,里面存储着自己的路由信息
    整个应用只有一个 router,可以通过组件的$router属性获取到。

多级路由 ---P120

多级路由是为了实现 子页面部件跳转,父组件不销毁

  • 配置路由规则,使用 children 配置项
routes: [
  {
    path: "/home",
    component: Home,
    //通过children配置子级路由
    children: [
      {
        path: "news", //此处一定不要写:/news,底层已经加了 /
        component: News,
      },
      {
        path: "message", //此处一定不要写:/message
        component: Message,
      },
    ],
  },
];
  • 跳转(要写完整路径):<router-link to="/home/news">News</router-link>

路由的 query 参数 ---P121

可用于 父 => 子 传递参数,可以传递任意类型的数据。

  • 在父组件传递参数
<!-- ?id=666&title=你好 为 query参数,to的字符串写法  -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>

<!-- 跳转并携带 query参数,to的对象写法,适用于传多个参数 -->
<router-link
  :to="{
    path: '/home/message/detail',
    query: {
      id: 666,
      title: '你好',
    },
  }">跳转</router-link>
  • 在子组件接收参数:$route.query.id, $route.query.title;

命名路由 ---P122

简化路由的跳转

<!-- 1. 给路由命名: -->
router 中 children 数组对象的 name 配置项
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>
<!--简化后,直接通过名字跳转 -->
<router-link :to="{ name: 'hello' }">跳转</router-link>
<!--简化写法配合传递query参数 -->
<router-link
  :to="{
    name: 'hello',
    query: {
      id: 666,
      title: '你好',
    },
  }">跳转</router-link>

路由的 params 参数 ---P123

  • 配置路由,声明接收 params 参数
{
  name: "myname", //给路由命名
  component: Home,
  path: '/detail/:id/:title', //使用占位符声明接收params参数
}
  • 传递参数
<!-- 跳转并携带 params参数,to的字符串写法 -->
<router-link :to="/detail/666/你好">跳转</router-link>
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link
  :to="{
    name: 'myname',
    params: {
      id: 666,
      title: '你好',
    },
  }">跳转</router-link>

特别注意: 路由携带 params 参数时,若使用 to 的对象写法,则不能使用 path 配置项,必须使用 name 配置!

  • 接收参数:$route.params.id; $route.params.title;

路由的 props 配置 ---P124

谁接收 data,在谁的路由对象中配置 props

{
 name:'xiangqing',
 path:'detail/:id',
 component:Detail,
 //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
 props:{a:900}

 //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有 params 参数通过props传给 Detail 组件
 props:true

 //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过 props传给Detail组件
 props(route){
  return {
   id:route.query.id,
   title:route.query.title
  }
 }
}

使用场景

控制路由跳转,浏览器历史记录的模式为 替换

浏览器的历史记录有两种写入方式:分别为pushreplace
push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push

开启replace模式

<router-link replace :to="/home/news">toNews</router-link>

编程式路由导航 ---P126

使用场景

js代码语法糖 进行路由跳转,让路由跳转更加灵活

相关 API:

this.$router.push({
  name: "detail",
  params: {
    id: xxx,
    title: xxx,
  },
}); //相当于点击路由链接(可以返回到当前路由界面)

this.$router.replace({
  name: "detail",
  params: {
    id: xxx,
    title: xxx,
  },
}); //用新路由替换当前路由(不可以返回到当前路由界面)

this.$router.forward(); //前进
this.$router.back(); //后退
this.$router.go(1); //可前进也可后退,请求下一个记录路由

缓存路由组件 ---P127

使用场景

让不展示的路由组件保持挂载,不被销毁。

使用方式

<keep-alive include="Detail">
    <router-view></router-view>
</keep-alive>
  • 不加 include 属性时,所有的路由组件都会被缓存。
  • include 属性的值为要缓存的路由组件的名称。
  • include=["A","B","C"] 属性的值可以是一个数组,数组中可以写多个要缓存的路由组件的名称。

两个新的生命周期钩子 ---P128

使用场景

路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

export default {
  name: "A",
  activated() { // 路由组件被激活时触发。
    console.log("A组件被激活了");
  },
  deactivated() { // 路由组件被失活时触发。
    console.log("A组件失活了");
  },
}

路由守卫 ---P129~132

router.js 中配置路由守卫

回调函数中的 to 为跳转的路由对象,from 为当前的路由对象。

  • 全局前置-路由守卫 ---P129
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
	console.log('前置路由守卫',to,from)
	if(to.meta.isAuth){ //判断是否需要鉴权
		if(localStorage.getItem('school')==='atguigu'){
			next()
		}else{
			alert('名不对,无权限查看!')
		}
	}else{
		next()
	}
})
  • 全局后置-路由守卫 ---P130
// 全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || '硅谷系统'
})
  • 独享-路由守卫 ---P131
{
  name:'xinwen',
  path:'news',
  component:News,
  meta:{isAuth:true,title:'新闻'},
  beforeEnter: (to, from, next) => { //独享路由守卫,就只对某个路由进行限制,无后置路由守卫
    console.log('独享路由守卫',to,from)
    if(to.meta.isAuth){ //判断是否需要鉴权
      if(localStorage.getItem('school')==='atguigu'){
        next()
      }else{
        alert('学校名不对,无权限查看!')
      }
    }else{
      next()
    }
  }
},
  • 组件内-路由守卫 ---P132
    通过路由规则进入
    通过路由规则离开
export default {
  //通过路由规则,进入该组件时被调用
  beforeRouteEnter (to, from, next) { 
    console.log('About--beforeRouteEnter',to,from)
    if(to.meta.isAuth){ //判断是否需要鉴权
      if(localStorage.getItem('school')==='atguigu'){
        next()
      }else{
        alert('学校名不对,无权限查看!')
      }
    }else{
      next()
    }
  },
  //通过路由规则,离开该组件时被调用
  beforeRouteLeave (to, from, next) {
    console.log('About--beforeRouteLeave',to,from)
    next()
  }
}

history 模式和 hash 模式 ---P133

使用场景:

总体来说 history 模式 使用较多,因为较为美观。

对于一个 url 来说,什么是 hash 值?

#及其后面的内容 就是 hash值。hash 值不会包含在 HTTP 请求中,即 hash 值不会带给服务器。

hash 模式 对比 history 模式

hash 模式 history 模式
地址中永远带着#号,不美观。 地址干净,美观。
兼容性较好。 兼容性和 hash 模式相比略差

hash 若以后将地址通过第三方手机 app 分享,若 app 校验严格,则地址会被标记为不合法。

history 应用部署上线时需要后端人员支持,解决刷新页面服务端 404 的问题。配一下 nginx 即可。前端也要做个 404 界面。

P134~P135 element-ui 组件库

Vue UI 组件库

移动端常用 UI 组件库

  1. Vant https://youzan.github.io/vant
  2. Cube UI https://didi.github.io/cube-ui
  3. Mint UI http://mint-ui.github.io
    PC 端常用 UI 组件库
  4. Element UI https://element.eleme.cn
  5. IView UI https://www.iviewui.co

终于看完了🎉🎉🎉
vue2.7 支持 compositin api,所以我要将本文中的案例,全部用其实现一遍

vue3

项目地址

pnia 学习

官方文档

可以认为 pinia 就是一个特殊的组件,

state => data,
action => function,
getter => computed,

再将其换成组合式 api 写法,就跟写普通组件的感觉是一样的

  • 先定义 仓库,在 main.js 中引入
  • 创建 stores 文件夹,数据模块分别进行存放,
  • 在组件中,引入store文件,通过方法创建 store 对象,然后将 state 和 getter 解构赋值并响应式,action 解构赋值即可

vue-router@4.x

路由传参 props

在路由表中设置参数,在组件 props 中接收

本文作者:Gavin's blog

本文链接:https://www.cnblogs.com/isgavin/p/17266867.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @ 2023-03-28 21:43  悠悠江水  阅读(117)  评论(0编辑  收藏  举报