• Vue3学习笔记 - 禹神YYDS


    1. 教程介绍

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=1

    • 本篇vue3,内容比较新,比如有setup语法糖用法;只是他使用TS,并不是JS;不过JS也比较熟悉了,也可以学习下TS的语法,
    • 课程使用 TypeScript + 组合式API(另一种叫选项式) + setup语法糖
    • 核心:ref / reactive / computed / watch / 生命周期
    • 常用:hooks / 自定义ref / 路由 / pinia / mitt
    • 重点: 组件通信 / 响应式API

    2-3. Vue3介绍,创建工程

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=2
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=3

    • vite创建工程
    • 工程文件介绍
    • 如何启动前端文件,看package.json,并看scripts,有dev,就可以运行npm run dev

    4. 编写App组件

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=4

    • main.ts
    • .vue文件基础3个标签

    5. 简单的效果

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=5

    • vue2写法,制作一个组件
    • vue3能写vue2的语法

    6. OptionsAPI与CompositionAPI

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=6

    • 关于vue2与vue3的写法差别

    7-9. Setup概述,Setup的返回值,与Setup与Vue2的兼容关系

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=7
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=8
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=9

    • export default的setup里没有this可以用
    • 变量没有定义成响应式的问题
    • setup的生命周期高于beforeCreate
    • 返回一个渲染函数
    • setup与vue2的写法可以同时存在,并说明兼容性问题

    10. Setup语法糖

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=10

    • script setup与script需要统一的语言
    • 安装插件 npm i vite-plugin-vue-setup-extend -D ;支持setup里加name标签;需要在vite.config.ts里引入
      在这里插入图片描述

    11. Ref创建基本类型响应式数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=11

    <template>
      <div class="person">
        <h3> 姓名:{{ name }}  </h3>
        <h3> 年龄:{{ age }} </h3>
        <h3> Tel:{{ tel }} </h3>
        <h3> Adrr:{{ addr }} </h3>
        <h3>
          <button @click="changeName">修改名称</button>
          <button @click="changeAge">修改年龄</button>
        </h3>
      </div>
    </template>
    
    <script lang="ts" setup name="Person">
      import {ref} from 'vue'
    
      let name = ref("张三")
      let age  = ref(18)
      let tel = "13222222222"
      let addr = "*******"
    
      const changeName = () => {
        name.value = "ZW"
      }
    
      const changeAge = () => {
        age.value += 1
      }
    </script>
    
    <style scoped>
    .person {
      font-size: 1.2rem;
      color: #222222;
      background-color: #efefef;
      padding: 30px;
    }
    </style>
    

    12. Reactive创建 对象类型的响应式数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=12

    • Proxy,代理,构造函数
    • reactive,可以写数组等各类对象
    • reactive,不管有多少层级,都可以改
    <template>
      <div class="car">
        <h3> 汽车:{{ car.brand }}  </h3>
        <h3> 价格:{{ car.price }} </h3>
        <h3>
          <button @click="changePrice">修改价格</button>
        </h3>
      </div>
    </template>
    
    <script lang="ts" setup name="Car">
      import {reactive} from 'vue'
    
      let car = reactive({brand:'byd', price:10})
    
      const changePrice = () => {
        car.price += 10
      }
    
    </script>
    

    13. Ref创建 对象类型的响应式数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=13

    • ref定义的对象,内部是Proxy对象,即用reactive定义的

    14. Ref与Reactive的区别

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=14

    • ref定义的对象,内部是Proxy对象,即用reactive定义的
    • reactive不能修改整个对象,需要用到Object.assign(obj, {…})的形式去修改
    • 若使用ref,这可以通过obj.value = {…},直接修改对象

    15. toRefs与toRef

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=15

    • 通过toRefs,把一个reactive对象,变成多个ref对象
    <template>
      <div class="person">
        <h3> 姓名:{{ person.name }}  </h3>
        <h3> 年龄:{{ person.age }} </h3>
        <h3>
          <button @click="changeName">修改名称</button>
          <button @click="changeAge">修改年龄</button>
        </h3>
      </div>
    </template>
    
    <script lang="ts" setup name="Person2">
      import {reactive, toRefs} from 'vue'
    
      let person = reactive({
        name:"张三",
        age:18
      })
    
      let {name, age} = toRefs(person)
    
      const changeName = () => {
        name.value += "~"
      }
    
      const changeAge = () => {
        age.value += 1
      }
    </script>
    
    • toRef,改掉一个
    let nl = toRef(person, 'age')
    
    • 通过toRef与toRefs把数据展开后,形成响应式数据,修改此响应式数据,原reactive的数据也回跟着修改

    16. computed计算属性

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=16

    • 关于v-model在input的使用; v-model可以实现双向绑定,即改变input里的值,变量的值也跟着改变
    • 关于computed的应用,并与函数的调用比较(函数调用多次,没有缓存)
      在这里插入图片描述
    • computed的数据是是ref的格式。
    • 把computed写成可读写的格式
      在这里插入图片描述

    17. watch监视 - ref监视基本数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=17

    • 格式:
      在这里插入图片描述
    • watch这里不需要加.value,因为watch监视的4类数据,需要是ref等格式
    • watch返回的是一个停止函数
      在这里插入图片描述

    18. watch监视 - ref监视对象数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=18

    • 监视ref定义的对象类型,是监视对象的地址,即不对对象全部赋值,而只对对象其中某属性赋值是无用的
    • 通过开启deep属性,来开通监视里面的属性
      在这里插入图片描述
    • immediate = true,开始立即监视,一运行就先执行监视一遍
      在这里插入图片描述
    • 一般情况就写一个value,新值
    • watch 3个参数:被监视的数据,监视的回调,配置对象(deep, immediate …)

    19. watch监视 - reactive监视对象数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=19

    • 监视reactive类型数据,默认开启的是深度监视

    20. watch监视 - 监视ref或reactive对象类型的某个属性

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=20

    • 需要制作一个getter函数,就是有一个返回值的函数形式
      在这里插入图片描述
    • 监视属性,是一个对象类型的时候,不需要getter函数形式,可以直接写
      在这里插入图片描述
    • 但是,当整体改变的时候,不会启动监听,所以优化下这类型的写法
      在这里插入图片描述

    21. watch监视 - 监视由可监视类型组成数组

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=21
    在这里插入图片描述

    • 对象监视默认都是用getter函数

    22. watchEffect

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=22

    • 用watch去实现,需要指定监视谁
      在这里插入图片描述
    • 使用watchEffect,开始会监视一遍
    • watchEffect会自动分析监视的对象
      在这里插入图片描述

    23. 标签的ref属性

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=23

    • 若用id获取dom,会存在重复的情况
    • 使用ref,在html里打上标记,就不会冲突,使用ref(),可以获取此标签
      在这里插入图片描述
    • 在style加入scoped,形成局部样式,不影响其他vue的样式
    • 若在组件加入ref,并获取;并不能获得子组件里的数据
    • 需要使用defineExpose来定下,可以看的数据
      在这里插入图片描述

    24. 关于TS的用法

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=24

    • 定义接口
      在这里插入图片描述
    • 定义对象
      在这里插入图片描述
    • 定义数组对象,泛型
      在这里插入图片描述
    • 定义成类型
      在这里插入图片描述
      在这里插入图片描述
    • 另一种写法
      在这里插入图片描述

    25. Props的使用

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=25

    • reactive传泛型
      在这里插入图片描述
    • 设计一个可无的属性,加?
      在这里插入图片描述
    • 用props来传递参数与接收参数
      在这里插入图片描述
      在这里插入图片描述
    • 这样写,不能打印调试,利用返回值获得传递值
      在这里插入图片描述
    • 传递对象数组
      在这里插入图片描述
    • 接收list,并限制类型
      在这里插入图片描述
    • 并限制必要性,加?号表示可有可无
      在这里插入图片描述
    • 默认值设置
      在这里插入图片描述
    • define开头的函数,是不需要引入的

    26-28. 生命周期

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=26
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=27
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=28

    • v-if,如果为false,会把组件销毁;v-show,只是隐藏,不会销毁
    • vue3,创建与setup是一样的,就是直接写在setup里
    • onBeforeMount
      在这里插入图片描述
    • onMounted
      在这里插入图片描述
    • onBeforeUpdate 与 onUpdated
      在这里插入图片描述
    • onBeforeUnmount 与 onUnmounted
      在这里插入图片描述
    • 关于父子的运行,是先运行子,在运行父

    29. Hooks的写法

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=29

    • 制作2个功能的代码
      在这里插入图片描述
    • hooks的作用是把相同的功能,组合在一起,先建立2个以use开头的ts文件
      在这里插入图片描述
    • useDog.ts
      在这里插入图片描述
    • 应用在vue里
      在这里插入图片描述
    • hooks里,还可以用生命周期函数,computed
      在这里插入图片描述

    30-31. 路由的基本用法

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=30
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=31

    • 点击菜单,产生路径的变化,触发router的规整识别,装载对应组件

    路由运行级别规则

    1. 确定哪里是导航区,哪里是展示区
    2. 设置路由器
    3. 自定路由规整(什么路径,对应什么组件)
    4. 开发对应的vue组件

    准备工作

    1. 安装路由 npm i vue-router
    2. 在src里建立router文件夹

    将建立路由器

    1. 在router文件夹里,建立index.ts文件
    2. 编写一个路由器代码
    import {createRouter, createWebHistory} from "vue-router"
    import Home from '@/components/Home.vue'
    import Car from '@/components/Car.vue'
    import Person from '@/components/Person.vue'
    
    const router = createRouter({
        history: createWebHistory(),
        routes:[
            {path:"/home",component:Home},
            {path:"/car",component:Car},
            {path:"/person",component:Person}
        ]
    })
    
    export  default router
    

    main.ts里挂载路由

    import './assets/main.css'
    
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    
    const app = createApp(App)
    app.use(router)
    app.mount('#app')
    

    路由运用于页面

    <template>
      <div class="app">
        <h2>Vue路由测试</h2>
        <div class="nav">
          <RouterLink to="/home" active-class="active">首页</RouterLink>
          <RouterLink to="/car" active-class="active">汽车</RouterLink>
          <RouterLink to="/person" active-class="active">人员</RouterLink>
        </div>
        <div class="main-content">
          <RouterView></RouterView>
        </div>
      </div>
    </template>
    
    <script setup lang="ts">
      import {RouterView, RouterLink} from 'vue-router'
    </script>
    
    <style scoped>
    h2{background-color: #222222}
    .main-content{
      width: 200px; height: 200px;
      border: 1px #ffffff solid;
    }
    a.active{color: aqua}
    </style>
    
    

    32. 路由的两个注意点

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=32

    • 注意点1:
    • 路由组件(页面)放在pages或views文件夹,一般组件放在components文件夹
    • 路由组件,一般是通过路由的规则渲染出来的
    • 一般组件,是嵌入到页面中的,以 * 出现的
    • 注意点2:
    • 默认是把路由组件卸载掉的
    • 可以通过keep-alive来维持不卸载
    • 可以通过transition实现简单页面动画

    33. 路由的工作模式

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=33

    • history模式:
    • 优点:Url路径不带#号,接近传统的Url
    • 缺点:后期项目上线,需要服务器端配合处理路径问题,否则404
    • hash模式:
    • 兼容性更好,不需要服务器配置
    • 不美观,路径上带#号

    34. 路由,to的对象写法

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=34

    在这里插入图片描述

    35. 路由,命名路由

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=35

    • 在路由定义的时候,给一个name值
      在这里插入图片描述
    • 通过name来进行跳转
      在这里插入图片描述

    36. 路由,嵌套路由

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=36

    • 制作嵌套路由的routes
      在这里插入图片描述
    • 编写RouterLink与RouterView
      在这里插入图片描述

    37. 路由,传参,query

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=37

    • query模式,params模式
    • query直接写在路由后面?a=a&b=b
    • 获取参数
      在这里插入图片描述
    • 使用模板字符串的方式,来写url
      在这里插入图片描述
    • 使用对象的query的写法
      在这里插入图片描述
    • 在路由器的子路由中,写个name,RouterLink这里可以直接写name进行跳转
      在这里插入图片描述
    • 把query接受的进行展开,为了不丢失响应式,需要用toRefs
      在这里插入图片描述

    38. 路由,传参,params

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=38

    • 需要在路由里,写上占位参数
      在这里插入图片描述
    • url写法,这里不能用path,而必须用name
      在这里插入图片描述
    • params里不允许用数组的形式
    • params可传可不传的参数,在后面加?号
      在这里插入图片描述

    39. 路由,路由的props配置

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=39

    • 路由配置
      在这里插入图片描述
    • 加了props的参数,相当于在Detail里,进行参数传递(第一种写法),只支持params
      在这里插入图片描述
    • 使用props参数
      在这里插入图片描述
    • 第2种写法,函数写法,参数是一个route参数,里面有query与params,选择返回哪个
      在这里插入图片描述
    • 第3种写法,对象写法,里面的传递的props是固定的
      在这里插入图片描述

    40. 路由,replace属性

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=40

    • 浏览的历史记录有push与replace模式。push模式是一直叠加记录(默认);replace是只记录一条
    • 改成replace模式,需要在RouterLink里加入replace
      在这里插入图片描述

    41. 路由,编程式导航

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=41

    • 简单的编程式导航跳转
      在这里插入图片描述
    • router.push里的写法与RouterLink to的写法是一致的
      在这里插入图片描述

    42. 路由,重定向

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=42

    • 在路由配置里,加一个路由规整
      在这里插入图片描述

    43-45. Pinia 的安装与引入

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=43
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=44
    https://www.bilibili.com/video/BV1Za4y1r7KE?p=45

    • vue2使用vuex,vue3可以私用pinia
    • 安装pinia,npm i pinia
    • 在main.ts里加入pinia
      在这里插入图片描述

    46. Pinia 存储+读取数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=46

    • 加入store文件夹
      在这里插入图片描述
    • 里面建立ts文件,名称与components的保持一致
      在这里插入图片描述
    • 在count.ts里写的格式,export的名字,规范use+模块名+Store;defineStore第一个参数同样是模块名
      在这里插入图片描述
    • 使用pinia
      在这里插入图片描述
    • 在reactive与Store里面的变量,都不需要使用value

    47. Pinia 修改数据

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=47

    • 数据可以直接修改(方法1)
      在这里插入图片描述
    • 当数据很多的时候,通过$patch,批量变更(方法2)
      在这里插入图片描述
    • 通过触发一个actions的函数来修改(方法3)
      在这里插入图片描述
    • actions函数需要定义
      在这里插入图片描述

    48. Pinia store ToRefs

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=48

    • 通过storeToRefs来拆解store的数据,性能高于toRefs
    • 若直接拆解,就丢失响应式
      在这里插入图片描述

    49. Pinia getters

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=49

    • 通过gettes,实现计算属性的作用
      在这里插入图片描述
    • 另一种写法,若用this,就不能用=>箭头函数
      在这里插入图片描述

    50. Pinia $subscribe的使用

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=50

    • 创建一个数据变化的监听
      在这里插入图片描述
    • 默认store模块里
      在这里插入图片描述

    51. Pinia store组合式写法

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=51

    • 类似与setup用法
      在这里插入图片描述

    52. 组件通讯,方式1,props

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=52

    • 父传子
      在这里插入图片描述
    • 子传父
      (方法1)
      在这里插入图片描述
      (方法2)直接使用函数
      在这里插入图片描述

    53. 组件通讯,方式2,自定义事件

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=53

    • 通过$event来获得事件对象,并和参数一起使用
      在这里插入图片描述
    • 父亲定义函数事件,由子来触发
      在这里插入图片描述
    • 还能传递参数
      在这里插入图片描述
    • 官方推荐,自定义函数,可以用XX-XX的方式来命名

    54. 组件通讯,方式3,mitt

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=54

    • 消息发布与订阅
    • 安装 npm i mitt
    • 建立一个emitter代码
      在这里插入图片描述
    • emitter.ts代码
      在这里插入图片描述
    • 基本用法
      在这里插入图片描述
    • onUnmounted去卸载
      在这里插入图片描述

    55. 组件通讯,方式4,v-model

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=55

    • v-model本质用法展示
      在这里插入图片描述
    • 组件里实现
      在这里插入图片描述
    • 划红线的少断言
      在这里插入图片描述
    • 关于$event,在父子的不同
      在这里插入图片描述

    56. 组件通讯,v-model的一些细节

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=56

    • 通过v-model:newName;来修改子组件的命名
    • 子组件:defineProps([“newName”]) 与 const emit = defineEmits([“update:newName”])
    • 并可以写多个v-model

    57. 组件通讯,方式5,$attrs

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=57

    • 祖与孙通讯
    • 父组件,写props传递
      在这里插入图片描述
    • 子组件,直接抛给孙组件
      在这里插入图片描述
    • $attrs是没有被props拿走的变量
    • v-bind="{x:20, y:20}"就等于父组件的一个个的props的写法

    58. 组件通讯,方式6,$refs 与 $parent

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=58

    • 通过ref , 修改子组件的属性
      在这里插入图片描述
    • 子组件要抛出对应属性,父才能修改
      在这里插入图片描述
    • 通过 $refs可以获取所有子组件
      在这里插入图片描述
      在这里插入图片描述
    • 通过$parent可以获取父的组件,父组件先对外抛出
      在这里插入图片描述
    • 子组件获取父组件,进行操作
      在这里插入图片描述

    59. ref的value规则

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=59


    60. 组件通讯,方式7,provide与inject

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=60

    • 也是祖孙之间传递,不需要中间人
    • 父用provide向下传递数据
      在这里插入图片描述
    • 孙拿到数据 inject
      在这里插入图片描述
    • 用默认值,来推断类型
      在这里插入图片描述
    • 把修改函数,传到孙,实现孙到父的操作;先在父把函数对外抛出
      在这里插入图片描述
    • 孙接收处理
      在这里插入图片描述

    61. 插槽-默认插槽

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=61

    在这里插入图片描述

    • slot标签内,可以写一个默认内容

    62. 插槽-具名插槽

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=62
    在这里插入图片描述

    • 一个简编的写法,语法糖,使用#号
      在这里插入图片描述

    63. 插槽-作用域插槽

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=63
    在这里插入图片描述

    • 通过slot设置props,把子组件的变量传给父组件;父组件通过template v-slot来获得全部的传递过来的变量
    • 可以直接解构
      在这里插入图片描述
    • slot里面可以有name属性,那么template的写法可以v-slot:myName ,默认名为 default

    64. shallowRef 与 shallowReactive

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=64

    • shallowRef 与 shallowReactive 只能用1层

    65. readonly 与 shallowReadonly

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=65

    • 为了数据的安全性,shallowReadonly只管理第1层为只读

    66. toRaw 与 makeRaw

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=66

    • toRaw,可以让响应式数据,变成非响应式
    • markRaw,不让一个数据,变成响应式的

    67. customRef,自定义Ref

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=67
    在这里插入图片描述

    • 结合Hooks,形成模块

    68. Teleport

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=68

    • 防止内容在页面中被渲染出app外面,可以加入teleport进行页面渲染指定
      在这里插入图片描述

    69. Suspense

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=69

    • 用于子组件setup里写了异步请求的时候,可以用Sespense
      在这里插入图片描述

    70. 全局API

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=70

    • app.component,注册全局组件
      在这里插入图片描述
    • app.config,设置一些默认属性,尽量不要这样用,不推荐
      在这里插入图片描述
    • app.directive,定义一个dom的属性
      在这里插入图片描述
      在这里插入图片描述
    • app.mount 与 app.unmout,app的挂载与卸载
    • app.use,使用组件,比如pinia等

    71. 非兼容性改变

    https://www.bilibili.com/video/BV1Za4y1r7KE?p=71

  • 相关阅读:
    KONICA MINOLTA China | 柯尼卡美能达-SMB扫描问题
    微信小程序写一个将图片对象转成base64字符串的函数
    ArcGIS QGIS学习一:打开shp、geojson地图变形变扁问题(附最新坐标边界下载全国省市区县乡镇)
    PPL攻击详解
    JavaEE初阶-网络编程
    Pytorvh之Vision Transformer图像分类
    浅谈c/c++中main(),int main(),void main(),int main(void)四者之间的区别
    vue中使用 eslint+prettier
    一、Maven-单一架构案例(创建工程,引入依赖,搭建环境:持久化层,)
    使用sass开发web-components组件
  • 原文地址:https://blog.csdn.net/qq_17523181/article/details/138338999