看源码,github,vue-next,在tag选择相对稳定的版本
在代码上写debugger
打包配置加上sourcemap,debugger定位到源码
vue3基础语法
1.methods中this指向
methods中不能用箭头函数,因为使用箭头函数后,this指向window
2.vs生成代码片段
3.模板语法
vue与react
-
Mustache双大括号语法
-
v-once,只渲染一次,可用于优化性能
-
v-text,v-html
-
v-pre,{{message}}直接显示
-
v-cloak,在编译时设置css,[v-clock]{dispaly:none},闪屏问题
-
v-bind,绑定属性,语法糖 :
- :class="{'active': boolean}" boolean:data里的响应式变量
- :class="['active', title, {'isBlue': boolean}]" title、boolean:data里的响应式变量
- :style="{color: finalColor, fontSize: '30px'}" finalColor:data里的响应式变量
- :style=[{color: finalColor}, {fontSize: '30px'}] finalColor:data里的响应式变量
- 动态属性 :[name]="finalName" name、finalName:data里的响应式变量
- 绑定一个对象 v-bind="info"等价于 :name=”shan“ :age=”16“,会自己将对象里的属性绑定到元素上
-
v-on,绑定事件,语法糖@
- v-on:click="btnClick" @click="btnClick"
- 多个事件 v-on="{click: btnClick, mousemove: mouseMove}"
- 传参 @click="btnClick(event
-
条件渲染 v-if、v-else-if、v-else;v-show
-
template 不可见的包裹元素,可与v-if、v-for搭配使用
-
循环渲染 v-for
-
数组 v-for="(item, index) in arr"
-
对象 v-for="(value, key, index) in obj"
-
数字 v-for="(num, index) in 10"
-
vue将监听数组的变更方法进行了包裹(改变数组)
- push/pop/shift/unshift/splice/sort/reverse
-
产生新数组
- filter/concat/slice
-
-
computed 计算属性:会基于它们的依赖关系进行缓存。当依赖的数据发生变化,计算属性才会重新进行计算
computed: { fullName: { get: function(){ return this.firstName + "-" + this.lastName }, set: function(newValue){ console.log(newValue) } } }
5.watch 侦听器:只侦听info的引用变化,对内部属性不做出响应
deep: true深层监听immediate: true立即执行一次
表单绑定
v-model
-
<input type="text" v-model="message"> -
语法糖,实际两操作
:value = "message"v-bind 绑定一个 value 属性@input = "message = $event.target.value"v-on 给当前绑定 input 事件
-
修饰符
- v-model.lazy:将@input变为@change
- v-model.number:v-model默认赋值为string,number可改为number
- v-model.trim
组件化开发
- 注册全局组件
app.component("component-a", {template: "我是组件a"})
webpack
-
视频上的node版本v14.15.5,npm是6.14.11
- 我的
- 我的
-
webpack is a static module bundler for modern JavaScript applications
-
webpack是一个静态的模块化打包工具,为现代JavaScript应用程序
-
打包bundler
-
静态static:打包成静态资源部署到静态服务器
-
模块化module:支持各种模块化开发,ES Module、CommonJS等
-
CommonJS
- 导出:
module.exports = {one: 1, two: 2} - 导入:
let {one, two} = require("./a.js")
- 导出:
-
ES6 的 Modules
- 导出:
export - 导入:
import
- 导出:
-
-
现代modren:现代前端问题,优化等
-
-
-
对应目录01webpack
-
npm init npm install webpack webpack-cli -D - 安装vscode插件Live Server
loader-帮助加载模块
- 对特定的模块类型进行转换
npm install css-loader style-loader less-loader -D
npm install --save-dev postcss-loader postcss
npm install postcss-preset-env -D
npm install file-loader -D
npm install url-loader -D
- css
-
less-loader解析.less文件,css-loader将.css文件解析,style-loader将其插入
-
postcss
-
一个通过JavaScript来转换样式的工具
-
可以通过添加插件进行一个css的转化和设配,比如添加浏览器前缀、css新属性适应等
-
可以在postcss.config.js中配置插件,然后在loader中引入,也可以直接在loader里配置
- 插件autoprefixer添加前缀
- 插件postcss-preset-env更强大,且包含了autoprefixer的功能
-
2.图片
-
file-loader,图片,帮助处理import/require()方式引入的文件资源
- import oneImage from '../img/1.png'
- 要把图片当成一个模块去引入,不然打包时找不到对应图片
-
url-loader,可以将较小文件转成base64的URL
- 对服务器高并发有优化作用。不处理的话,加载一张图片需要向服务器发送一次请求,将其转化为base64后,会集成到js文件中,随着js文件的请求一起传给浏览器,由浏览器解析显示,不需要单独请求
-
asset module type
- webpack5新特性
- 加载字体,和图片类似
plugin-执行更加广泛任务
- 比如打包优化、资源管理、环境变量注入等
npm install clean-webpack-plugin -D
npm install html-webpack-plugin -D
npm install copy-webpack-plugin -D
- CleanWebpackPlugin 删除dist文件夹
- HtmlWebpackPlugin 插入html模板
- CopyWebpackPlugin 复制public目录下的部分文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require("webpack")
const CopyWebpackPlugin = require("copy-webpack-plugin")
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html",
title: "Webpack5"
}),
new DefinePlugin({
BASE_URL: "'./'",
}),
new CopyWebpackPlugin({
patterns: [
{
from: "public",
to: "./",
globOptions: {
ignore: [
"**/index.html" // 忽略的文件
]
}
}
]
})
]
mode和devtool
mode: "development", // 开发阶段,打包上线->production
devtool: "source-map", // 建立js映射文件,方便调试代码和错误
Babel - JS编译器
- 将写的源代码转为浏览器可识别的另外一段源代码。语法转化、源代码转换
npm install @babel/core @babel/cli -D 核心代码,必须安装
npm install @babel/plugin-transfrom-arrow-functions -D 转化箭头函数
npm install @babel/plugin-transfrom-block-scoping -D 转化块级作用域
以上两个也在下面这个中集成
npm install @babel/preset-env -D
webpack用babel
npm install babel-loader @babel/core -D
npm install @babel/preset-env -D
-
推荐阅读,简易编译器代码
-
Babel编译器执行原理(理解)
-
babel可直接在module中配置,也可写配置文件babel.config.json
devServer
-
两种常用监听文件改动自动打包方法
- 直接配置watch:true + vscode插件live-server(自动刷新浏览器)
- webpack-dev-server
-
webpck-dev-server
-
npm install webpack-dev-server -D -
#package.json "scripts": { "build": "webpack", "serve": "webpack serve", }, -
配置项contentBase,主要用于开发阶段,不复制,直接去访问
- webpack4的contentBase,webpack5要用static
- 打包阶段,用copy-webpack-plugin复制一份到打包文件里
-
模块热替换(HMR,Hot Module Replacement)
-
在运行过程中,替换、添加、删除模块,以模块更新为单位,无需重新刷新整个页面
-
-
-
Http和socket
- Socket长连接,即时通信,通过心跳包判断
- Http短连接,客服端发送请求->和服务器建立连接->服务器做出相应->断开链接
-
-
proxy
- 代理服务器(和浏览器的域名/端口一致(记得是))
- 代理服务器和API服务器没有跨域问题,就可以解决浏览器的跨域问题了
-
resolve模块,解析文件路径
- extensions 扩展名
- alias 别名
-
vue
npm install vue@next
写.vue文件
npm install vue-loader@next @vue/compiler-sfc -D
-
vue打包后有不同版本
- cdn引入一般是vue.global.js,全局暴露一个vue对象
- runtime的版本不能解析template,没有编译器
-
import { createApp } from 'vue/dist/vue.esm-bundler' // 要选择版本 const app = createApp({ template: `<h1>Vue render</h1>`, data() { return {} } }); app.mount("#app")
-
vsCode对.vue文件,安装 volar插件
-
webpack配置vue
-
const { VueLoaderPlugin } = require("vue-loader/dist/index") module.exports = { mudule: { relus: [ { test: /.vue$/, loader: "vue-loader", } ] }, plugins: [ new DefinePlugin({ // 警告,建议配置,利于tree-shaking(打包时,没用到的不打包) __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, }), new VueLoaderPlugin() ] }
-
webpack配置分离
npm install webpack-merge -D-
#package.json "build": "webpack --config ./config/webpack.prod.config.js", "serve": "webpack serve --config ./config/webpack.dev.config.js",
Vue Cli
npm install @vue/cli -g
npm update @vue/cli -g
vue create 项目的名称
- vue-cli service 源码解析,视频10,时间00:50:00,没看懂
Vite
-
浏览器可解析ES6 module,但是不能加载.ts,.vue等文件,且依赖包的管理不足(会请求很多依赖文件)
-
vite
- 安装对应工具包(postcss、less)会自动转化代码,复杂的还是需要额外的配置文件
- serve ,可以将ts、less转化为js代码(es6),还是一个个文件的形式
- build,会将node_moudle里的引入包做预打包,再次打包时会直接用之前的,减少打包时间
-
package.json
-
"scripts": { "serve": "vite", "build": "vite build", "perview": "vite preview" }
-
-
组件化开发
- vscode插件 vue3-snippets-for-vscode、vetur
组件的拆分和嵌套
- components
组件的css作用域
组件通信
父子组件
-
父->子 props属性
-
type类型:String、Number、Boolean、Array、Object、Date、Function、Symbol
-
数组和对象默认值必须从工厂函数获取,
default() { return {}|[]}- return 会返回一个新对象或数组,各组件间就不会相互影响
-
非props的Attribute
-
当子组件为单个根节点时,非prop的Attribute将自动添加到根节点的Attribute中,如class、style
-
不想继承时,子组件设置inheritAttrs: false
-
当子组件有多个根节点时,会报警告,需手动指定将属性绑到哪个节点上
子->父 $emit 触发事件
-
-
-
非父子组件通信
-
provide、inject
- 不管层级多深,父组件可以作为所有子组件的依赖提供者
-
mitt全局事件总线
npm install mitt-
#util/eventBus.js import mitt from 'mitt' const emitter = mitt() export default emitter -
// 发送 btnClick(){ emitter.emit("shan", {name: "shan"}) } // 监听 emitter.on("shan", (info)=>{}) // 取消 emitter.all.clear() function onFun(){} emitter.on('foo',onFun) // 监听 emitter.off('foo',onFun) // 取消监听
插槽
-
匿名插槽
-
具名插槽
-
父 <template v-slot:center> 内容 </template> 父简写 <template #center> 内容 </template> 子 <slot :name="center"></slot>
-
-
动态插槽
-
父 <template v-slot:[name]></template>
-
-
渲染作用域
- 父级模板的所用内容在父级作用域中编译
- 子模板的所用内容在子作用域中编译
-
作用域插槽
- 插槽可以访问到子组件中的内容,比如渲染数组元素时使用插槽
-
父 <show-names :name="names"> <template v-solt="slotProps"> <button>{{slotProps.item}}-{{slotProps.index}}</button> </template> </show-names> 子 <div> <template v-for="(item,index) in names" :key="item"> <slot :item="item" :index="index"></slot> </tempalate> </div>
动态组件
-
<component :is="currentTab"></component>
keep-alive
-
保存组件状态,不销毁
-
<keep-alive> <component :is="currentTab"></component> </keep-alive> -
属性
- include,名称匹配的组件被缓存,匹配组件自身的name选项
- exclude,名称匹配的组件不被缓存
- max,缓存组件达到这个数字,最近没有被访问的组件会被销毁
Webpack代码分包
- 默认情况下,在构建组件树的过程中,组件和组件间通过模块化直接形成依赖,webpack在打包时会将组件模块打包到一起,比如一个app.js
- 随着项目扩大,app.js文件过大,会造成首屏的渲染速度变慢。
- 对于一些不需要立即使用的组件,单独对它们进行拆分,拆分成小的代码块chunk.js
异步组件
-
import
-
vue3
-
import { defineAsyncComponent } from 'vue'; const AsynCategory = defineAsynComponent(()=>import("./AsyncCategory.vue")) // 或者对象写法 const AsynCategory = { loader: ()=>import("./AsyncCategory.vue"), // 工厂函数 loadingComponent: 加载时的运行组件, errorComponent: , delay: 2000, // 在显示loadingComponent前的等待事件 }
-
$refs
-
绑定一个元素上 <h2 ref="title"></h2> 绑定组件实例上 <nav-bar ref="navBar"></nav-bar> 取 this.$refs.title,dom元素 取 this.$refs.navBar,组件实例
root
- this.$parent,父组件实例
- this.$root,根组件实例
组件生命周期
组件v-model
-
父 <s-input v-model:model-value="message"></s-input> 相当于 <s-input modelValue="message" @update:model-value="message = $event"></s-input> 子 <div> <input v-model="value"> </div> { ..., props: { modelValue: String, }, emits: ["update:modelValue"], // 自定义表单,比较优雅的写法 computed: { value: { set(value) { this.$emit("update:modelValue", value) }, get() { return this.modelValue; } } } }
vue3过渡和动画实现
transition
-
vue提供了transition的封装组件,可以给单个组件或元素加过渡效果
- 条件渲染(v-if、v-show)
- 动态组件
- 组件根节点
-
<transition name="shan"> // type - animation 或 transition <h2 v-if="show" type="animation">Hello</h2> </transition> // 淡入淡出 transition <style scoped> .shan-enter-from, .shan-leave-to { opacticy: 0 } .shan-enter-to, .shan-leave-from { opacity: 1 } .shan-enter-active, .shan-leave-active { transition: opacity 1s ease; } </style> // 弹 animation <style scoped> .shan-enter-active { animation: bounce 1s ease; } .shan-leave-active { animation: bounce 1s ease reverse; } @keyframes bounce { 0% { transform:scale(0) } 50% { transform:scale(1.2) } 100% { transform:scale(1) } } </style> -
当插入/删除包含transition组件中的元素时
- 判断目标元素是否应用css过渡或动画,如果有,在恰当事件添加/删除 css 类名,没有的话,插入/删除操作会立即执行
-
还有其他属性,看vue官方文档
animate.css
- 第三方动画库,跨平台动画库
npm install animate.css-
#main.js import "animate.css" -
bounceInUp动画库提供的名称 .shan-enter-active { animation: bounceInUp 1s ease; } 也可以使用自定义class <transition enter-active-class="animate__animated animate__fadeInDown"> <h2 v-if="show">Hello</h2> </transition>
gsap库
-
通过 js 为css属性、SVG、Canvas等设置动画
-
transition组件有对应js钩子
-
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" ...... > </transition>
-
transition-group
- 列表动画,移除、插入、移动、交错(data-Index(el.dataset.index),delay)
Mixin
-
vue组件中的可复用功能
mixins: [demoMixin]
-
Mixin合并规则
- data,合并,发生冲突,保留组件自身数据
- 生命周期钩子函数,合并到数组中,mixin先
- 指为对象的选项(methods/components/directives),合并,发生冲突(key相同),取组件的
extend(了解)
- 了解,可被mixin替代
extends: BasePage
Composition API
15、16
-
options API对应属性编写对应功能模块
- 实现某个功能时,对应代码逻辑会被拆分到各个属性,阅读性差
-
Composition API能将同一逻辑相关的代码放在一块,阅读性更好
setup函数
-
setup函数中没有this
-
可以替代vue2的大部分选项,如methods、computed、watch、data、生命周期等
-
参数
-
props
- 父组件传递过来的属性会放入props对象
-
context
- attrs:所有非prop的attribute
- slots
- emit
-
-
返回值,给模板使用
script setup
<script setup></script>
reactive API
import { reactive } form "vue"
const state = reactive({
name: "shan",
counter: 100
})
- 使用reactive处理数据后,再次使用会进行依赖收集
- 当数据发生改变时,收集到的依赖会进行对应的响应式操作(比如更新界面)
- 其他API
reactive 其他API
- isProxy,是否由 reactive/readonly 创建的proxy
- isReactive
- isReadonly
- toRaw
- shallowReactive
ref API(推荐使用,利于代码分离)
import { ref } form "vue"
const name = ref("shan")
- ref 返回一个响应式对象,该对象作为一个响应式的引用
- 模板引用ref值时,会自动进行解包,可以直接用{{name}}
- 在setup函数内部,依然是一个ref引用,要使用name.value的方式
toRefs
- 将reactive对象里所有属性转为ref,建立引用
-
const info = reactive({name: "shan", age: 16}) let {name,age} = toRefs(info) //直接解构就不是响应式数据,得用toRefs
toRef
- 将reactive对象里其中一个属性转为ref,建立引用
-
const info = reactive({name: "shan", age: 16}) let age = toRef(info, "age")
customRef(自定义ref)
-
export default function(value) { let timer = null; return customRef((track, trigger) => { return { get() { track(); return value }, set(newValue) { clearTime(timer); timer = setTimeout(()=>{ value = newValue; trigger() },1000) } } }) }
模板中使用ref
-
<h2 ref="title"></h2> <script> import {ref, watchEffect} from 'vue'; export default { setup() { const title = ref(null) // 初始值给null watchEffect(() => { // title.value },{ flush: "post" // 挂载后操作 }) return { title // 返回了,就可以直接在模板用 } } } </script>
其他 ref API
- unref 等价于
val = isRef(val) ? val.value : val - isRef
- shallowRef
- triggerRef:手动触发和 shallowRef 相关的副作用
readonly
import { readonly } form "vue"
const nameRead = readonly("shan")
- reactive或ref会返回一个响应式对象,传给其他组件时,不希望被修改,可以用readonly
- readonly返回原生对象的只读代理,proxy的set方法被劫持
侦听
computed
const fullName = computed(() => firstName.value + lastName.value)
- 接受一个getter函数,或者get和set的对象,返回ref对象
watchEffect
-
基本使用
- 传入会立即执行一次,并在执行时收集依赖(响应式数据)。依赖发生变化时,函数会再次执行
-
watchEffect(() => { console.log("age",age.value) }
-
停止侦听,返回值 stop
-
清除副作用,参数onInvalidate
- watchEffect 的 函数即将重新执行或侦听被停止(stop被调用)时会执行onInvalidate传入的回调函数
-
const stop = watchEffect((onInvalidate) => { const timer = setTimeout(()=>{ // 模拟网络请求 },2000) onInvalidate(()=>{ clearTimeout(timer) }) console.log("age",age.value) } const changeAge = () => { age.value++ if(age.value > 25) { stop() } }
-
执行时机(flush)
- 默认值pre,元素挂载前执行
- post,元素挂载后
-
watchEffect(()=>{ let content = titleRef.value }, { flush: "post" })
watch
-
与option中的类似
-
与watchEffect比较
- 惰性,第一次不会直接执行
- 具体说明哪些变量发生变化触发执行
- 访问状态变化前后的值
-
单个数据源
-
1.getter函数,newValue,oldValue是本身 2.传入reactive对象,newValue,oldValue也是reactive对象 3.传入reactive对象,newValue,oldValue是value值本身 watch(()=>info.name, (newValue,oldValue) => { // newValue,oldValue }, { deep:true, immediate: true })
-
-
多个数据源
-
watch(()=>[...names], (newValue,oldValue) => { // newValue,oldValue => 普通的值 })
-
生命周期钩子
- beforeCreate、created没有对应的,在setup里直接写就行,setup围绕着着两个周期执行
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- unmounted
- onActivated
- onDeactivated
provide、inject
// 一般包层readonly,组件间数据传递保持单向
provide("name", readonly(name))
const name = inject("name")
hook示例
-
useCounter
-
useTitle
-
useScrollPosition
-
#App.vue <div class="scroll"> <div>scrollX: {{scrollX}}</div> <div>scrollY: {{scrollY}}</div> </div> <script> import useScrollPosition from './hook/useScrollPosition' export default { setup() { const {scrollX, scrollY} = useScrollPosition() } return { scrollX, scrollY } } </script> <style> .scroll { position: fixed; right: 30px; bottom: 30px; } </style> -
#useScrollPosition.js export default function() { const scrollX = ref(0) const scrollY = ref(0) document.addEventListener("scroll", () => { scrollX.value = window.scrollX scrollY.value = window.scrollY }) return { scrollX, scrollY } }
-
-
useLocalStorage
-
#App.vue // 取值 const data = useLocalStorage("name") // 保存值 const data = useLocalStorage("name", "shan") // 改值 data.value = "xiao" -
#useLocalStorage.js export default function(key, value) { const data = ref(value) if(value) { window.localStorage.setItem(key, JSON.stringify(value)) }else { data.value = JSON.parse(window.localStorage.getItem(key)) } watch(data, (newValue) => { window.localStorage.setItem(key, JSON.stringify(value)) }) return { data } }
-
h函数(渲染函数)
-
vue会将template中的HTML转换为VNode,VNode组合在一起形成树结构(VDOM)
-
h()是一个创建vnode的函数,creatVNode()
-
h()参数
- HTML标签名,组件,必需
- props,可选
- 内容,可选
-
基本使用
-
<script> import { h } from 'vue'; export default { render() { return h("h2", {class: "title"}, "HelloWorld") } } </script>
-
-
实现计数器
-
插槽的使用 - 官网也有说明
-
vue中使用jsx
-
jsx通过Babel进行转换(React编写jsx也是通过babel转换)
-
-
在Babel中配置插件(高版本vue已有集成)
npm install @vue/babel-plugin-jsx -D-
#babel.config.js module.exports = { presets: [ "@babel/preset-env" ], plugins: [ "@vue/babel-plugin-jsx" ] }
-
使用实例
-
<script> export default { render() { return <div>HelloWorld</div> } } </script>
-
-
vue3高级用法
自定义指令 18
-
对DOM元素进行底层操作,这个时候用自定义指令
-
局部指令
-
<template> <div> <input type="text" v-focus> </div> </template> <script> export default { // 局部指令 directives: { focus: { mounted(el, bindings, vnode, preVnode) { el.focus() // 输入框内自带此函数 } } }, setup() {} } </script>
-
-
全局指令
-
app.directive("focus", { mounted(el, bindings, vnode, preVnode) { el.focus() // 输入框内自带此函数 } })
-
-
指令的生命周期
- created(vue2 - 无)
- beforeMount(vue2 - bind)
- mounted(vue2 - inserted)
- beforeUpdate(vue2 - 无)
- updated(vue2 - componentUpdated)
- beforeUnmount(vue2 - 无)
- unmounted(vue2 - unbind)
Teleport-vue3新内置组件
- 移动元素位置
-
<teleport to="放在哪#shan"></teleport>
vue插件
-
# main.js app.use(pluginObject) # plugin_object.js export default { install(app) { // } }
路由
Vuex
vue2和vue3
-
template
- vue2 template模板中只能有一个根元素
- vue3 template中允许有多个根元素
-
过滤器
- vue3不支持过滤器,用计算属性computed或方法method替代
-
$children
- vue3移除了$children
其他
filter、map、reduce
深拷贝和浅拷贝
-
Object.assign({}, item) 浅拷贝
-
用lodash
const obj = _.clone(info)浅拷贝const obj = _.cloneDeep(info)深拷贝