1. computed的使用
- 作用
- 在模板中需要对数据进行复杂处理,且可能多次使用的情况下,使用计算属性可使数据结构更加清晰。
- 如果依赖数据没有发生变化,计算属性会从缓存中获取,不会重新计算。
- 模板里面的数据通过v-model绑定后,如果这个数据是通过计算属性得来的,那么访问的时候触发get,get()里面return什么,v-model就绑定什么。当这个数据被修改的时候,就会触发到set方法,修改的值就会当作参数,传给set。
// 以下是computed实现全选/全不选的部分代码 <template> <span>全选:</span><input type="checkbox" v-model="allDone" /> </template> <script setup lang="ts"> import { ref, computed, watchEffect } from "vue"; // isActive 是用来计算未完成的todoList的数量 const isActive = computed(() => { return todoList.value.filter((item) => !item.done).length; }); const allDone = computed({ // 在get()里面, get: () => { return isActive.value === 0; }, // 在切换全选的时候 遍历todoList 把done字段改成和allDone一样即可 set: (val) => { todoList.value.forEach((element) => { element.done = val; }); }, }); </script>
- 优势
- 计算属性会基于他们的依赖关系进行缓存,当数据不发生变化时候,计算属性是不需要重新计算的。当依赖的数据发生变化,在使用时,计算属性依然会重新进行计算。
- vue3的computed
- computed 返回的是一个ref对象
2. methods
- 注意事项:
- 里面不可以使用箭头函数。因为箭头函数绑定了父级作用域的上下文(指向 window ),所以 this 不会指向组件实例。
3. 基本指令
- v-once 用于指定元素或者组件只渲染一次。当数据发生变化时。元素或者组件以及所有的子元素都将视为静态内容跳过。(可用于性能优化)
- v-text / v-html / v-pre
- v-cloak
- v-bind (绑定一个或者多个属性值,或者向另一个组件传递props值)
- 绑定class的两种方式
- 对象语法
<div :class="{ 'active': isActive, nba: true }"></div>- 也可以直接绑定一个对象
<div :class="classObj"></div>
- 数组语法
<div :class="['active', nba]"></div>
- 对象语法
- 绑定style的两种方式
- 对象语法
div :style="{ fontSize: '12px', color: 'red' }"></div>同样也可以绑定一个定义好的对象<div :style="[styleObj1, styleObj2]"></div>这样可以将多个样式对象应用到元素上。
- 对象语法
- 绑定属性名
:[name]="值" - 绑定一个对象的所有属性
v-bind="obj"obj对象会被拆解成元素的各个属性。
- 绑定class的两种方式
- v-on (@)绑定事件
- 修饰符(对事件进行了一些特殊的处理)
- .stop 禁止冒泡 调用 event.stopPropagation()
- .prevent 禁止默认事件 调用 event.preventDefault()
- 示例
<form @submit.prevent></form>
- 示例
- .capture 添加事件监听器时使用事件捕获模式,即内部元素触发的事件先在此处理,然后才交由内部元素进行处理。
- .self
- .{keyAlias} - 按键修饰符
- .once - 只触发一次回调
- .left - 只点击鼠标左键时触发
- .right - 只点击鼠标右键时触发
- .middle() - 只点击鼠标中键时触发
- .passive - {passive: true}模式添加侦听器
- 基本使用
- 可以给一个元素绑定多个事件
<div v-on="{ click: btnClick, mouseove: mouseMove }"></div>
- 可以给一个元素绑定多个事件
- 参数传递
- 如果该方法不需要额外参数, 那么方法后的()可不添加
- 如果方法本身有一个参数,那么默认会将原生事件的event参数传递进去
- 如果需要同时传入某个参数, 同时需要event时,可以通过$event传入事件。
<div v-on="{ click: btnClick, mouseove: mouseMove }"></div>
- 修饰符(对事件进行了一些特殊的处理)
4. slot (插槽)
- 具名插槽
- 即有名字的slot,若没有指定name属性的话, 会默认有 "default"。
<slot name="header></slot> - 使用的时候,可以在template元素上使用 v-slot 指令,并以 v-slot 的参数形式提供其名称
<template v-slot:header></template>。template元素中的所有内容都将会被传入相应的插槽。简写可以写为<template #header></template> - v-slot 只能用于template上,除独占默认插槽以外。
- 即有名字的slot,若没有指定name属性的话, 会默认有 "default"。
5. 使用localStorage实现本地存储
- 相关Api
- localStorage.getItem(key) //获取指定key对应的值
- localStorage.setItem(key, value) //接收键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值
- localStorage.removeItem(key) //从存储中删除该键名
- localStorage.clear() // 清空存储中的所有数据
- 注意事项
- api里的键和值的类型均为字符串,我们一般存储的是JSON,但是localStorage会自动将其转换称字符串格式,所以可以使用JSON.stringify()来将JSON转换为字符串, 读取的时候要使用JSON.parse()将JSON字符串转换为JSON对象
6. scoped
- 作用
- 使样式私有化,即定义的CSS就只会应用到当前组件上的元素上。
- 原理
- 主要通过postcss转译实现。标签和样式的属性上都新增了 data-v 的前缀(唯一且不重复的动态属性),确保只在当前组件上生效
- 其它
- 如果想要在scoped内部写全局样式,可以使用 :global来标记
- 也可以使用 v-bind 函数, 直接在css中使用JavaScript中的变量
4.侦听响应式数据变化
4.1 watchEffect
- 使用
- 首先,watchEffect 传入的函数会立即执行一次, 并且在执行的过程中会收集依赖;其次只有在收集的依赖发生变化时,watchEffect()传入的函数才会再次执行。
- 停止侦听 - 调用stopWatch()就行
const stopWatch = watchEffect(() => {}); - 清除副作用
4.2 watch
- 基本使用
- 当定义在data里的数据发生变化,且想要做一些逻辑上的处理的时候,可使用侦听器。
- 监听的是定义在data里的属性或者是props进行传值的内容
// 需要监听的值,以及变化后的新值和变化前的旧值 watch(value, (newValue, oldValue) => {}, { immediate: true, // 立即执行侦听 deep: true, // 深度侦听 });- 默认情况下,侦听器只会针对监听的数据本身的改变(内部发生的改变时不能侦听),即如果侦听的是一个对象,watch是可以侦听到对象整体的变化的,但是不能侦听到对象的属性的变化。如果要侦听的话,需使用 deep: true。
- 注意事项
- watch需要侦听特定的数据源,并在回调函数中执行副作用
- 默认情况它是惰性的,只有当被侦听的源发生变化时才会执行回调
4.3 $watch API
- 用法同watch,但是其是有返回值的。通常在created生命周期里面使用
4.3 区别
- watchEffect 将在方法的任何依赖项发生更改时运行,watch 跟踪一个或多个特定的响应性属性,并且仅在该属性发生更改时运行。
- 默认情况下,watch 是惰性的,因此仅当依赖项更改时才会触发。watchEffect 在创建组件后立即运行,然后跟踪依赖关系。但是,我们可以为 watch 传递一个 immediate 属性,使其在初始化时运行。
5. v-model
- 基本使用
- 可以在表单 input、textarea以及select元素上创建双向数据绑定,他会根据控件类型自动选取正确的方法来更新元素。
- 负责监听用户的输入事件并更新数据
- 原理
- v-bind 绑定value属性的值
- v-on 绑定input事件监听到函数中,函数回获取最新的值赋值给绑定的属性中
<input type="text" name="" id="" v-model="currentIndex" /> // 等价于 // 默认情况下 v-model在进行双向绑定时,绑定的是input事件,即每次内容输入后就将最新的值和绑定的属性进行同步。 <input type="text" :value="currentIndex" @input="currentIndex = $event.target.value" /> - 修饰符
- .lazy 将绑定的事件切换为change事件,只有在提交时(例如回车)才会触发
- .number 将v-model绑定的值转换为数字类型
- .trim 过滤输入的首尾空白字符
- 绑定checkbox
- 单个勾选框的时候为boolean值,此时input的value不影响v-model的值
- 多个复选框时,因为可以选中多个,所以对应的data是个数组,当选中某一个时,就会将input的value添加到数组中。
组件化开发
1. 注册组件
- 注册组件分为以下两种:
- 全局组件:在任何其他的组件中都可以使用的组件
- 局部组件:只有在注册的组件中才能使用的组件
1. 注册全局组件
- 全局组件需要使用我们全局创建的app来注册组件
- 通过 component方法传入组件的名称,组件对象(可以有自己的代码逻辑,比如有自己的data、computed、methods)即可注册一个全局组件
- 定义组件名称的方法有 kebab-case(短横线分隔符)、PascalCase(驼峰标识符 - 首字母大写)
- 如果使用短横线分隔符的话,引用组件也必须用短横向分隔符;而驼峰标识符的话,在引用组件的时候,两种命名法都可以引用。
- 之后可以在App组件的template直接使用这个全局组件
createApp(App).use(router).mount("#app"); App.component("MyComponent", { template: "", data() { return {}; }, });
2. 注册局部组件
- 局部注册是在我们需要使用到的组件中,通过components属性来注册,components选项对应的是一个对象,对象中的键值对是 组件名称:组件对象
2.组件之间的通信
1. 父子组件的通信
- 父组件传递给子组件:通过props属性
- props是定义在组件上的一些自定义属性,父组件给属性赋值,子组件通过属性的名称取到对应的值
- props传值的方式
- 字符串数组,数组中的字符串是自定义属性的名称
props: ['value'] - 对象类型,可以指定要传递的类型、是否必须及默认值等等。
props: { title: String, value: { type: String, // 类型 defalut: 'hi', // 默认值 required: true // 是否必须 } } - props传入的类型是一个对象或者数组的时候,这里的默认值必须是一个函数
- 字符串数组,数组中的字符串是自定义属性的名称
- 子组件传递给父组件:通过$emit触发事件
- 具体步骤
- 在子组件中定义好事件,之后在父组件中以v-on的方式传入要监听的事件名称,并且绑定到对应的方法中,最后,在子组件触发事件,根据事件名称触发对应的事件。
// setup 语法 // 在setup中必须使用 defineProps 和 defineEmits API来声明props和emits(无需引入)。 const emit = defineEmits(["handleClick"]); function handleClick(index: number) { emit("handleClick", index); } // props 的用法 - 第一个参数传类型, 第二个参数传默认值 const props = withDefaults( defineProps<{ options: EChartsOption // echarts option的类型 width?: string // ? 代表是可选类型 height?: string // ? 代表是可选类型 }>(), { width: '100%', height: '360px' } ) // vue2/vue3的写法 - 可是个数组,也可以是个对象(可以对传递的参数进行验证) emits: ['handleClick'] emits: { addOne: null, addTen: function (payload) {} }
- 在子组件中定义好事件,之后在父组件中以v-on的方式传入要监听的事件名称,并且绑定到对应的方法中,最后,在子组件触发事件,根据事件名称触发对应的事件。
2. 非prop的Attribute
- 定义 当我们传递给一个组件某个属性,但是该属性并没有定义对应的prop或者emits,就称之为非props的attribute。常见的包括class、style、id属性。
3. Provide和Inject - 用于非父子组件之间的通信
- 使用情景 比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容。在这种情况下,如果使用props沿着组件链逐级
4. 全局事件总线mitt库
- Vue3从实例中移除了 off、
Webpack相关知识
-
为什么要使用webpack
随着项目越来越复杂,会采用组件化的方式来进行开发,即意味着每个组件都会有自己的模板、脚本逻辑、样式等。当然我们依然可以把它们抽离到单独的js、css文件中,但是他们还是会分离开来,也包括我们的script是在一个全局的作用域下,很容易出现命名冲突的问题,并且代码为了适配一些浏览器,必须使用es5的语法;所以在编写代码完成之后,依然需要通过工具对代码进行重新构建。所以在真实开发中,我们可通过 后缀名为 .value 的single-file components(单文件组件来解决),并且可以使用webpack或者vite或者rollup等构建工具来对其进行处理。- 使用SFC(单文件的特点)
- 代码高亮
- es6、commonJS的模块化能力
- 组件作用域的css
- 可以使用预处理器来构建更加丰富的组件,比如 TypeScript、Babel、Less等
- 使用SFC(单文件的特点)
-
webpack的默认打包
- 在目录下直接执行
webpack(使用的是全局 webpack),webpack会查找当前目录下的src/index.js作为入口,如果没有此文件,就会报错。当然也可以指定入口和出口。
npx webpack --entry ./src/main.js --output-path ./build - 会生成一个dist文件夹,里面存放一个main.js的文件(被压缩和丑化了),这就是我们打包之后的文件。
- 在目录下直接执行
-
安装
npm install webpack webpack-cli –g # 全局安装 npm install webpack webpack-cli –D # 局部安装 -
创建局部的webpack
- 创建 package.json 文件,用来管理项目的信息,库依赖等
npm init - 安装局部的webpack
npm install webpack webpack-cli –D # 局部安装 - 使用局部的webpack
npx webpack - 在package.json中创建scripts脚本, 执行脚本打包即可
"scripts": { "build": "webpack" } npm run build(打包命令)- 通常可以在根目录下创建一个 webpack.config.js文件,来作为webpack的配置文件。
- 创建 package.json 文件,用来管理项目的信息,库依赖等
-
loader
5. 动画
1. transition
- 命名规则
- 如果没有指定transition的name属性,那么所有的class都是以v-作为默认前缀,反之如果有name属性,那么所有的class都会以name的属性值开头。
- 第三方库推荐
- animate.css
- 安装 - npm install animate.css
- 在 main.js 引入 - import "animate.css"
- 直接使用animate库中定义的 keyframes 动画/直接使用animate库提供给我们的类;
- gasp库(使用JavaScript来实现一些动画的效果)
- 安装 - npm install gasp
- animate.css
- 列表过渡 -
<transition-group>- 默认情况下,其不会渲染一个元素的包裹器,但是可以通过指定tag属性渲染
- 内部元素需要指定唯一的key属性
- css过渡的类会被应用在内部的元素中,而不是这个组/容器本身
- 过渡模式不可用,因为我们不再相互切换特有的元素
- transition组件的JavaScript钩子
6. vuex
- 使用场景
- 我们是使用组件化机制来搭建项目的,每个组件内部有自己的数据和模板。但是总有些数据是需要共享的,如当前登录的用户名,权限等数据,如果都在组件内部传递,会变得非常混乱。所以vuex就是相当于项目中的大管家,集中式存储管理应用中的所有组件的状态。
- 核心属性
- state - 定义数据
- getter
- mutation - 同步的修改数据,并在组件中使用commit去调用mutations。
- actions - 异步修改数据,并在组件中使用store.dispatch调用action
- modules
- 其它
- vuex对TypeScript的支持不好,更推荐Pinia。
7. vue-router
- spa (single page application) 单页面应用程序
- 优势: 路由跳转不需要刷新页面
- 实现原理
路由就是用来解析URL实现不同页面之间的跳转,目前是 hash 和 history两种方式 - 实现跳转的方式
- hash模式 (#)
在页面进行跳转的时候,hash值的变化并不会导致页面的刷新,只是会触发hashchange事件,通过对hashchange时间的监听,我们就可以在fn函数内部进行动态的页面切换window.addEventListener('hashchange',fn) - history模式 2014年以后,因为HTML5标准发布,浏览器多了两个API: pushState和replaceState。通过这两个API,我们可以改变URL地址,并且浏览器不会向后端发送请求。
- hash模式 (#)
面试常问
- v-if 和 v-show的区别
- 首先,v-show不支持template;
- 其次,v-show元素是通过css的display属性来进行切换的,其dom实际上都是有渲染的。v-if为false的时候,其对应的元素根本不会被渲染到dom中。
- 最后,元素需要在显示和隐藏之间频繁的切换就是用v-show,否则就使用v-if
- 定义methods里的方法时,不可以使用箭头函数
- 如果使用箭头函数的话,this指向window(箭头函数不绑定this)。
vue3
MVVM模型
vue3 带来的变化
- 使用proxy进行数据劫持
- 删除了一些不必要的api
- 由Option API 到 composition API
webpack基础知识
webpack is a static module bundle for modern JavaScript application
基本指令
-
安装 npm install webpack webpack-cli -g (-g 全局安装 / -D 局部安装)
-
打包
- 全局打包(不推荐) webpack
- 局部打包
- cd到项目里,执行 npm init / npm init -y 创建 package.json文件
- 安装开发/生产依赖 npm install webpack webpack-cli --save-dev 等价于 npm install webpack webpack-cli -D(开发依赖) 会创建 package-lock.json 记录了安装的各个依赖的版本号 和 node_modules
- 打包
// 方式一:找到node_modules 的 .bin目录下 的webpack文件 即输入 ./node_modules/.bin/webpack 等价于 npx webpack; // 方式二:在package.json的scripts定义打包方式 scripts: { build: "webpack" } //运行 npm run build -
指定打包的入口和出口
// 方式一:使用指令 `npx webpack --entry ./src/main.js --output-path ./build` // 方式二:新建 webpack.config.js 使用commonJS指定 entry 和 output
loader的使用 - 可以用来对模块的源代码进行转换
- style-loader 在html页面创建style标签,再把对应的css样式插入到页面上
- css-loader 将.css文件进行解析
- 安装指令:npm install css-loader -D
- 使用loader加载css文件
- 方式一:内联方式(非常少用),在引入css文件的时候
import "css-loader!../css/style.css!表分割 用css-loader加载style.css - 方式二:在webpack.config.js的导出对象上新增module属性 module属性里面有rules数组,数组里面是一个一个的对象
module.exports = { module: { rules: [ { test: /\.css$/ //正则表达式(.需要转义 即加上\ $表示以什么结尾) 表示以.css结尾的,就使用这个rule // 1. loader的写法(语法糖) // loader: "css-loader", // 表示以.css结尾的 就使用这个loader // 2. 完整写法 use: [ // 从右往左先读 "style-loader" "css-loader" // 也可以传参 等价于 { loader: "css-loader", options: {} } ] } ] } } - 方式一:内联方式(非常少用),在引入css文件的时候
- less-loader
- 安装指令
- npm install less-loader -D (安装less-loader)
- npm install less -D (安装less)
- 配置webpack.config.js
{ test: /\.less$/, use: [ "style-loader" "css-loader" "less-loader" ] }
- 安装指令
- postcss 工具 - 通过JavaScript来转换样式的工具 其可以帮助我们进行一些css的转换和适配 比如自动添加浏览器前缀 css样式的重置
- 安装指令
npm install postcss postcss-cli -D - 需要给浏览器添加前缀,所以需要安装 autoprefixer
npm install autoprefixer -D - 直接使用使用postcss工具,并且指定使用autoprefixer
npx postcss --use autoprefixer -o end.css ./src/css/style.css(-o 输出 即将style.css输出为end.css) - 也可以使用 postcss-preset-env 这个插件的功能会比 autoprefixer 强大
- 安装指令