VUE3 + Vite
安装 、 运行 、vscode插件
- 安装、运行
npm init vite@latest npm install npm run dev
- vscode插件:
- Vue Language Features
- TypeScript Vue Plugin
- 为什么 npm run dev 可以启动项目:
- 查找可执行文件然后执行
- 查找规则:先从本地的node_modules里找bin有没有vite可以执行的(.bin 目录里是一个个软链接),如果没有,就去npm install -g(全局包)里找,还没有就去环境变量里面找,如果还有没就报错。
模板语法
- v- 开头都是vue 的指令
- v-text :显示文本
- v-html :展示富文本
- v-if : 控制元素的显示隐藏(切换真假DOM)
- v-show :控制元素的显示隐藏(display none block Css切换)
- v-on :简写@ 用来给元素添加事件
- v-bind 简写: 绑定元素的属性Attr
- v-model : 双向绑定
- v-for :遍历元素
- v-once :性能优化只渲染一次
- v-memo : 性能优化会有缓存
vue虚拟DOM 和 diff算法
- 虚拟DOM就是通过JS来生成一个AST节点树
- diff算法:
- 无key: 替换、新增、删除
- 有key:前序对比算法、尾序对比算法、新节点如果是多出来的就挂载、旧节点如果是多出来就卸载、特殊情况乱序(最长递增子序列算法)
Ref全家桶
- ref():接受一个内部值并返回一个响应式且可变的 ref 对象
- isRef(): 判断是不是一个ref对象
- shallowRef: 创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的;(只改变简单数据类型,不改变复杂数据类型)(不可以和ref一起使用)
- triggerRef():强制更新页面DOM
- customRef: 自定义ref ; 是个工厂函数要求我们返回一个对象 并且实现 get 和 set; 适合去做防抖之类的
Reactive全家桶
- Reactive(object):用来绑定复杂的数据类型;返回一个对象的响应式代理。reactive 源码约束了我们的类型,只能传入object
- readonly(): 拷贝一份proxy对象将其设置为只读
- shallowReactive(): 只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图
Ref 与 Reactive 区别
- ref:支持所有的类型;reactive:只支持引用类型
- ref:取值赋值都要加.value; reactive不需要
to全家桶
- toRef: 如果原始对象是非响应式的就不会更新视图 数据是会变的;如果原始对象是响应式的是会更新视图并且改变数据的
- toRefs:批量创建ref对象;用于解构;
- toRaw:将响应式对象转化为普通对象
响应式原理
- vue2: 使用Object.definedProperty实现
- vue3: 使用Proxy
computed 计算属性
- 计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值
- 函数形式:只能取值不能修改
- 对象形式:可以修改也可以取值(get、set)
watch 侦听器
- 侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数
- watch(参数一,参数二,参数三)
- 参数一:数据源; 可以是: ref 、 reactive 、 一个函数返回一个值、 以上类型的值组成的 数组 []
- 参数二:回调函数;(新值,旧值)
- 参数三:对象,options配置项;immediate:创建时立即触发回调;deep:深度遍历(reactive默认);
watchEffect()
- 立即运行传入的一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
- let 返回值 = watchEffect(参数一,参数二)
- 第一个参数:运行的副作用函数;(用到几个监听几个 而且是非惰性 会默认调用一次)
- 第二个参数:可选的选项,用来调整副作用的刷新时机或调试副作用的依赖;
- flush : pre(组件更新前执行)、sync(强制效果始终同步触发) 、post(组件更新后执行)
- 调试 watchEffect:onTrigger
- 返回值:用来停止该副作用的函数
watch 和 watchEffect()区别
- watch:懒执行副作用;能更明确知道是哪个依赖发生变化;可以访问当前值和旧值
- watchEffect:非惰性;可以停止追踪;可以在调整副作用的刷新时机或调试副作用的依赖
computed 和 watch 区别
- 是否有缓存: computed有,watch没有
- 是否支持异步:computed不支持,watch支持
生命周期
- 用Vue3 组合式API 是没有 beforeCreate 和 created 这两个生命周期的;setUp替代
- onBeforeMount():读不到dom
- onMounted():可以读取dom
- onBeforeUpdate():获取更新之前的dom
- onUpdated():获取更新之后的dom
- onBeforeUnmount():组件卸载之前
- onUnmounted():组件卸载之后
- onErrorCaptured():在捕获了后代组件传递的错误时调用
- onRenderTracked():调试钩子,当组件渲染过程中追踪到响应式依赖时调用
- onRenderTriggered():调试钩子,当响应式依赖的变更触发了组件渲染时调用。
父子组件传值
父传子(defineProps)
- 父组件通过v-bind绑定一个数据
- 子组件通过 defineProps 接受传过来的值
- ts: defineProps<{title:string,data:number[]}>()
- 非ts: defineProps({title:{default:‘’,type:string},data:Array})
- ts特有默认值方式: withDefaults(defineProps<{title:string,data:number[]}>(),{title:“xx”,data:() => [1,2,3]})
子传父 (defineEmits)
- 子组件 是通过defineEmits派发一个事件
- 父组件接收子组件的事件
子组件暴露给父组件内部属性 (defineExpose)
- 子组件通过 defineExpose暴露
- 父组件通过ref拿到
动态组件
- 让多个组件使用同一个挂载点,并动态切换,这就是动态组件
- 挂载点使用component标签,然后使用v-bind:is=“组件”
- 场景:tab切换
插槽
- 子组件中的提供给父组件使用的一个占位符 slot标签
- 父组件可以在这个占位符中填充任何模板代码,填充的内容会替换子组件的标签
- 匿名插槽:子: slot标签; 父:v-slot
- 具名插槽:给插槽取个名字;一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中
- 简写 v-slot:xx 简写成 #xx
- 动态插槽:插槽可以是一个变量名
- #[xxx]
异步组件 & 代码分包 & suspense
- 异步组件:在大型应用中,可能需要将应用分割成小一些的代码块 并且减少主包的体积,这时候就可以使用异步组件
- 代码分包:父组件引用子组件 通过defineAsyncComponent加载异步配合import 函数模式便可以分包
- suspense: 组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。
<Suspense> <template #default> <Dialog> <template #default> <div>我在哪儿</div> </template> </Dialog> </template> <template #fallback> <div>loading...</div> </template> </Suspense>
Teleport传送组件
- 将模板渲染到指定的dom节点,不受父级属性影响,但data、prop数据依旧能够使用
- 类似 react 的 Portal
- 使用方法:通过to 属性 插入指定元素位置;disabled动态控制teleport
<teleport :disabled="true" to='body'> <A></A> </teleport
keep-alive缓存
- 切换子组件的时候,将缓存数据下来,再次切换回来数据还在
<keep-alive :include="" exclude="" :max="">组件</keep-alive> <keep-alive :max="10"> <component :is="view"></component> </keep-alive>
- include:需要缓存的组件; exclude:不需要缓存的组件; max:最大缓存数据
- 生命周期变化:
- 初次进入:onMounted > onActivated
- 退出:onDeactivated
- 再次进入:onActivated
transition 动画组件
- Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡:
- 条件渲染 、条件展示、动态组件、组件根节点
- 自定义 transition 过度效果,name属性自定义
- 过渡的类名:进入/离开过渡,有 6 个 class 切换
- v-enter-from、v-enter-active、v-enter-to、v-leave-from、v-leave-active、v-leave-to
- 自定义过度时间:duration
- transition 生命周期8个:
- @before-enter 、@enter、 @after-enter、 @enter-cancelled、@before-leave、@leave、@after-leave、@leave-cancelled
- appear
- 通过这个属性可以设置初始节点过度 就是页面加载完成就开始动画 对应三个状态
- appear-active-class、appear-from-class、appear-to-class
依赖注入 Provide / Inject
- 用于父组件向后代组件传递数据
- 类似react的useContext 上下文
- provide:可以在祖先组件中指定我们想要提供给后代组件的数据或方法; provide(key,传递的数据)
- inject:后代组件通过inject来接收数据;inject(key)
Mitt
- 用于兄弟组件之间传值
- 安装: npm install mitt -S
- .main.ts 初始化
- 使用方法:通过emit派发, on 方法添加事件,off 方法移除,clear 清空所有
- import { getCurrentInstance } from ‘vue’
- const instance = getCurrentInstance()
- emit派发: const emit = () => { instance?.proxy?.$Bus.emit(‘自定义事件名’,值)}
- on监听: instance?.proxy?.$Bus.on(‘事件名’,(值) =>{})
- 监听所有: instance?.proxy?.$Bus.on(‘事件名’,(*) =>{})
- 移除监听事件:instance?.proxy?.$Bus.off(‘事件名’,Fn)
- 清空所有监听:instance?.proxy?.$Bus.all.clear()
TSX
- 安装插件:npm install @vitejs/plugin-vue-jsx -D
- vite.config.ts 配置
- import vueJsx from ‘@vitejs/plugin-vue-jsx’;
- plugins: [vue(),vueJsx()]
- 修改tsconfig.json 配置文件
- “jsx”: “preserve”, “jsxFactory”: “h”,“jsxFragmentFactory”: “Fragment”
TSX使用
- 返回一个渲染函数 ; optionsApi ; setUp 函数模式
- 支持:v-model ; v-show ;
- 不支持:v-if ; v-for ;
- v-bind:变更为 直接赋值就可以使用;
- v-on:变更为 所有事件有on开头、事件名称首字母大写
- props: 变更为 类似reat
- Emit派发: 第二个参数中获取xx xx.emt(‘自定义事件名’,值)
unplugin-auto-import
- 配置完成之后使用ref reactive watch 等 无须import 导入 可以直接使用
深入V-model
- v-model 其实是一个语法糖 通过props 和 emit组合而成的
- prop:value -> modelValue (父组件:v-model=xxx 子组件:definedPropsmodelValue:类型())
- emit: input -> update:modelValue; (父组件不要写啥,子组件:definedEmit([‘update:modelValue’]) emit(‘update:modelValue’,值))
- 支持多个 v-model (父组件:v-model:nnn=xxx 子组件:definedPropsmodelValue:类型,nnn:类型() definedEmit([‘update:modelValue’,‘update:nnn’]) )
自定义指令 Directive
- 引入 import type { Directive } from ‘vue’
- 使用: let VXx:Directive<HTMLImageElement,string> = (el,binding) => {}
- 标签中:v-xx = mm
- 钩子函数(常用的):mounted 、update、unmounted
- 参数:
- el:当前绑定的DOM 元素
- binding: instance:使用指令的组件实例;value:传递给指令的值;oldValue:先前的值;arg:传递给指令的参数;modifiers:包含修饰符
globEager 、glob
- vite自带的导入图片
- 使用:import.meta.glob(‘…/xxx/x/.’) import.meta.globEager(‘…/xxx/xx/.’)
IntersectionObserver
- 异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法
- 可用于图片懒加载等
- js 构造函数
globalProperties 定义全局函数和变量
- 由于Vue3 没有Prototype 属性 , 使用 app.config.globalProperties 代替 然后去定义变量和函数
const app = createApp({}) app.config.globalProperties.$函数名 = () => {} app.config.globalProperties.$变量 = '值' 组件中: 标签内:$变量 ts内: 从vue中引入getCurrentInstance const app = getCurrentInstance app?.proxy.$变量
过滤器
- 在Vue3 移除了,可以使用全局函数代替Filters
编写vue3插件
- 思路:
- 在一个单独的文件中创建并导出它
- 先定义一个.vue组件,将需要暴露的方法属性通过 definedExporse暴露出来
- 定义一个相关的ts文件,把插件的方法和属性注册到全局
- export default {install:(app:App) => {}}
- 导入.vue组件,createVNode(组件) 创建虚拟dom; render(vnode,document.body)将虚拟dom渲染到页面中
- app.config.globalProperties 将方法或属性挂载到全局
- 在main.ts中进行注册
- 导入app.use(组件)注册
- TypeScript注册,必须要拓展ComponentCustomProperties类型才能获得类型提示
-
- 使用: 通过 getCurrentInstance 去使用
详解 Scoped 和 :deep 样式穿透
- Scoped: 通过在DOM结构以及css样式上加唯一不重复标记:data-v-hash 的方式,以确保唯一
- scoped渲染规则:
- 给HTML的DOM节点加一个不重复的 data 属性(如:data-v-123)来表示他的唯一性
- 在每句选择器的末尾 (编译后生成的css语句) 加一个当前组件的data属性选择器(如[data-v-123])来私有化样式
- 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
- :deep 样式穿透 : 用来改变 属性选择器的位置
- 例如改变el组件的样式时 在scoped中不能直接修改,原因是他在进行PostCss转化的时候把元素选择器默认放在了最后
- :depp() 就是用来改变属性选择器的位置
css Style 完整特性 (slotted、globad)
- 插槽选择器:slotted :slotted(类名){}
- 使用场景:A组件中定义了 插槽,父组件中通过v-slot传入模板代码;A组件像修改插槽传入的样式时可以使用
- 全局选择器:globad
- 之前想加入全局样式,是通过style标签不加 scoped
- 现在可以使用 :globad(xx){}
- 动态css
- 单文件组件的 style 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上;div{ color:v-bind(变量)}
- 如果是对象 v-bind 加引号 v-bind(“变量.xx”)
nextTick
- vue 更新dom是 异步 的,数据更新是 同步 的
- 当需要操作dom的时候,可以使用nextTick
- nextTick 就是创建一个异步任务,那么它自然要等到同步任务执行完成后才执行;可以在状态改变后立即使用,以等待 DOM 更新完成
- 用法:
-
- 回调函数: nextTick(() => { xxx })
-
- async awit
unocss原子化
- 减少了css体积,提高了css复用
- 减少了起名的复杂度
- 增加记忆成本
- 最好用于vite,webpack属于阉割版功能很少
函数式编程,h函数
- vue中写的template,经过一系列的编译最终生成VNode
- h函数就是直接用来生成VNode的一个函数,省略了一系列的编译
- h(参数一、参数二、参数三)
- 参数一:必填项,字符串(可以是html标签名、一个组件、函数组件)
- 参数二:可选的,对象(attribute、prop 、事件)
- 参数三:可选的,字符串/数组/对象(children 子节点)
- 例如 :h(“h2”, null, “Hello World”)
环境变量
- 他的主要作用就是让开发者区分不同的运行环境,来实现 兼容开发和生产
- npm run dev 就是开发环境 npm run build 就是生产环境
- Vite 在一个特殊的 import.meta.env 对象上暴露环境变量
- BASE_URL: 部署时的URL前缀
- MODE: 运行模式
- DEV:是否在dev环境
- PROD:是否是build 环境
- SSR:是否是SSR 服务端渲染模式
- 配置额外的环境变量:
- 在根目录新建env 文件、可以创建多个
如:.env.development .env.production - 修改启动命令
在 package json 配置 --mode env文件名称
- 在根目录新建env 文件、可以创建多个
Proxy跨域
- 当一个请求url的 协议、域名、端口 三者之间任意一个与当前页面url不同即为跨域
- 解决方法:
- jsonp
- cors :设置 CORS 允许跨域资源共享 需要后端设置
- Vite proxy:代理
vite.config.js/ts 进行配置
参考来源:https://blog.csdn.net/qq1195566313/category_11618172.html