深入Vue2
frontend
Vue2
学习内容参考 /在线运行
Element
学习内容参考 /视频教学
vue2
1. vue 实例
-
当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中
-
但是当使用Object.freeze(),会阻止修改现有的 property,也意味着响应系统无法再追踪变化。
var obj = {foo: 'bar' } Object.freeze(obj) new Vue({el: '#app',data: obj })
-
不要在选项 property 或回调上使用箭头函数,因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
2. 模板语法
-
render: 如果熟悉虚拟 DOM 并且偏爱 JavaScript 的原始力量,也可以不用模板,直接写渲染 (render) 函数,使用可选的 JSX 语法。
-
在站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。因为如果用户输入内容包含恶意脚本,这些脚本会被执行,并且直接解析并渲染 HTML 内容。而{{ }}会被转义为纯文本,会更安全。
-
js模板表达式 模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。不应该在模板表达式中试图访问用户定义的全局变量。
3. v-指令
-
指令支持动态参数
-
不推荐同时使用 v-if 和 v-for。因为当它们一起使用时,v-if 会优先于 v-for 被处理,这可能会导致一些意外的行为和性能问题。可以使用计算属性进行过滤, 也可以将 v-if 置于外层元素
-
v-for 在遍历对象时,会按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下都一致。如果你需要确保属性的遍历顺序是一致的, 可以使用map
-
替换数组: filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组
-
当ul标签使用v-for, 使用is渲染组件, is="todo-item" attribute。因为在 <ul> 元素内只有 <li> 元素会被看作有效内容。这样做实现的效果与 <todo-item> 相同,但是可以避开一些潜在的浏览器解析错误。这是因为这些结构有严格的子元素要求。例如,<ul> 元素只能包含 <li> 元素作为其直接子元素。查看 DOM 模板解析说明 来了解更多信息。
-
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
4. 组件
-
组件是可复用的 Vue 实例,所以它们与
new Vue
接收相同的选项 -
,一个组件的
data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,否则可能影响到其他实例 -
.prop
- 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里?) -
is渲染组件,使用.vue,template 是不会有限制的
-
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名
但是重申一次,如果你使用字符串模板,那么这个限制就不存在了。
-
这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 用作其初始值:
场景: 网络请求res.data中的属性可能会被提示未定义
props: ['initialCounter'], data: function () {return {counter: this.initialCounter} }
-
prop 验证
注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如
data
、computed
等) 在default
或validator
函数中是不可用的 -
组件可以接受任意的 attribute,从外部提供给组件的值会替换掉组件内部设置好的值。
-
class
和style
attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:form-control date-picker-theme-dark
。 -
若想要在一个组件的根元素上直接监听一个原生事件, Vue 提供了一个
$listeners
property,包含了作用在这个组件上的所有监听器Vue.component('base-input', {inheritAttrs: false,props: ['label', 'value'],computed: {inputListeners: function () {var vm = this// `Object.assign` 将所有的对象合并为一个新对象return Object.assign({},// 我们从父级添加所有的监听器this.$listeners,// 然后我们添加自定义监听器,// 或覆写一些监听器的行为{// 这里确保组件配合 `v-model` 的工作input: function (event) {vm.$emit('input', event.target.value)}})}},template: `<label>{{ label }}<inputv-bind="$attrs"v-bind:value="value"v-on="inputListeners"></label>` })
-
.sync
修饰符 处理组件之间的双向数据流 但vue3已移除 -
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
-
具名插槽 #
-
在每个
new Vue
实例的子组件中,其根实例可以通过$root
property 进行访问。// 获取根组件的数据 this.$root.foo
但是中大型应用就要使用vuex了
-
类似的,
$parent
property 可以用来从一个子组件访问父组件的实例但是会失控,所以推荐依赖注入
-
目录树组件循环引用,可以使用webpack 的异步 import
5. 过渡
-
vue在插入,更新或者移除DOM时,提供多种不同方式的应用过渡效果,包括以下工具
-
css 过渡和动画
-
第三方css动画库 Animate.css
-
js钩子函数
-
第三方js动画库,如velocity.js
-
5.1 单元素/组件的过渡
-
vue提供了transition的分装组件,为元素添加过度
<div id="demo"><button v-on:click="show = !show">Toggle</button><transition name="fade"><p v-if="show">hello</p></transition> </div> <style>//元素从进入到离开 过程.fade-enter-active, .fade-leave-active{transition:opacity .5s;}//元素在刚开始进入和离开时 动作.fade-enter, .fade-leace-to{opacity: 0} </style>
5.1.1 过渡的类名
在进入/离开的过渡中,会有 6 个 class 切换。
-
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。 -
v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。 -
v-enter-to
:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。 -
v-leave
:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。 -
v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。 -
v-leave-to
:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时v-leave
被删除),在过渡/动画完成之后移
5.1.2 自定义过度的类名
我们可以通过以下 attribute 来自定义过渡类名:
-
enter-class
-
enter-active-class
-
enter-to-class
(2.1.8+) -
leave-class
-
leave-active-class
-
leave-to-class
(2.1.8+)
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> <div id="example-3"><button @click="show = !show">Toggle render</button><transitionname="custom-classes-transition"enter-active-class="animated tada"leave-active-class="animated bounceOutRight"><p v-if="show">hello</p></transition> </div>
5.2 初始渲染的过度
<transition appear><!-- ... --> </transition>
5.2.1自定义css类名
<transitionappearappear-class="custom-appear-class"appear-to-class="custom-appear-to-class" (2.1.8+)appear-active-class="custom-appear-active-class" ><!-- ... --> </transition>
5.2.2 自定义js钩子
<transitionappearv-on:before-appear="customBeforeAppearHook"v-on:appear="customAppearHook"v-on:after-appear="customAfterAppearHook"v-on:appear-cancelled="customAppearCancelledHook" ><!-- ... --> </transition>
5.3 多个元素的过度
<transition><table v-if="items.length > 0"><!-- ... --></table><p v-else>Sorry, no items found.</p> </transition>
5.3.1 过渡模式
-
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。 -
out-in
:当前元素先进行过渡,完成之后新元素过渡进入。(常用)<transition name="fade" mode="out-in"><!-- ... the buttons ... --> </transition>
5.4 多个组件的过度
-
使用动态组件
<transition name="component-fade" mode="out-in"><component v-bind:is="view"></component> </transition>
5.5 列表过度
-
使用transition-group
<div id="list-demo" class="demo"><button v-on:click="add">Add</button><button v-on:click="remove">Remove</button><transition-group name="list" tag="p"><span v-for="item in items" v-bind:key="item" class="list-item">{{ item }}</span></transition-group> </div>
6. 可复用性&组合
6.1 JSX
7. 测试
-
Vue 组件通常包含
.vue
文件,里面包含模板、脚本和样式。这种单文件组件(SFC)格式并不是原生 JavaScript 或 TypeScript 能直接识别的。因此,vue-jest
使用 Babel 来将.vue
文件转换为可被 Jest 识别的格式。 -
Jest 本身依赖 Babel 来处理 Vue 单文件组件及 ES 模块。
babel-jest
可以帮你将非标准的 J
7.1 步骤
-
vue2
7.1.1 ts
-
安装jest
npm install jest --save-dev
-
配置jest
在根目录下创建jest.config.js
module.exports = {moduleFileExtensions: ['js', 'vue'],moduleNameMapper: {'^@/(.*)$': '<rootDir>/src/$1'},transform: {'^.+\.js$': 'babel-jest','.*\.vue$': 'vue-jest'},snapshotSerializers: ['jest-serializer-vue'],// 在Vue单元测试中使用了v-model, 需要添加一下配置,请参考官方文档.// https://vue-test-utils.vuejs.org/guides/common-tips.html#mocking-components-that-use-v-model// setupFiles: ['<rootDir>/tests/unit/setup.js'],testMatch: ['<rootDir>/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'],testURL: 'http://localhost/' }
-
moduleFileExtensions 中包含了Vue文件,这是允许Vue文件被编译并测试的必要配置。
-
moduleNameMapper 是用来解析@符号的。
-
transform 配置了如何转换代码,vue-jest 转换.vue文件,babel-jest 转换.js文件。
-
snapshotSerializers 在snapshot test中使用,使快照测试更加容易。
-
testMatch 配置了测试文件的匹配规则。
-
testURL 配置了测试时浏览器的URL。
-
-
编写测试用例
import { shallowMount } from '@vue/test-utils' import HelloWorld from '@/components/HelloWorld.vue'describe('HelloWorld.vue', () => {it('renders props.msg when passed', () => {const msg = 'new message'const wrapper = shallowMount(HelloWorld, {propsData: { msg }})expect(wrapper.text()).toMatch(msg)}) })
-
npm run jest 运行
7.1.2 babel
-
安装依赖
npm install --save-dev jest @vue/test-utils babel-jest vue-jest
-
配置Jest
-
在项目根目录添加jest.config.js
module.exports = {preset: '@vue/cli-plugin-unit-jest',transform: {'^.+\\.vue$': 'vue-jest','^.+\\.js$': 'babel-jest',},moduleFileExtensions: ['js', 'vue'],testMatch: ['**/tests/**/*.spec.js'], };
-
* 确保Jest能够识别和处理Vue组件以及js文件
-
创建测试文件
-
放在test文件夹下,以.spec.js结尾
//shallowMount 用于浅层挂载一个 Vue 组件,它只渲染组件的最外层,不会递归渲染子组件,适用于组件依赖的其他子组件较复杂时进行测试。 import {shallowMount} from '@vue/test-utils'; import HelloWorld from '@/components/HelloWorld.vue'; //describe 用于组织和分组相关的测试,括号中的 'HelloWorld.vue' 作为测试套件的名称,指明我们要测试的目标是 HelloWorld.vue 组件。 describe('HelloWorld.vue', () => {//it 函数用于定义一个测试用例,括号中的 'renders props.msg when passed' 是对测试的简短描述,意思是“当传递 msg 属性时,组件应该正确渲染出来”。it('renders props.msg when passed', () => {//我们将在测试中传递msg作为组件的 props,以测试它是否正确渲染出来。 const msg = 'Hello Jest';//shallowMount 用于浅层挂载 HelloWorld 组件。 //wrapper 是一个包装器对象,它包含了挂载后的组件实例,并提供了访问和操作组件的方法,比如获取 DOM 元素、触发事件等。 const wrapper = shallowMount(HelloWorld, {propsData: {msg}});//这一行是断言(assertion),它使用 Jest 的 expect 函数来验证测试结果。//wrapper.text() 获取组件的文本内容(包括组件的所有子元素)。//toMatch 用于检查文本是否包含指定的字符串 msg,即 'Hello Jest'。这个断言期望组件渲染的文本内容中包含传递的 msg。 expect(wrapper.text()).toMatch(msg);}); });
-
7.2 报错
-
由于未知原因,我的js项目竟然必须安装@types/jest,才可以正确引入jest,实在不知道为什么,先贴出来吧
-
yarn add --dev @types/jest
8. 规模化
8.1 路由
8.2 状态管理
-
Redux 事实上无法感知视图层,所以它能够轻松的通过一些简单绑定和 Vue 一起使用
8.3 服务端渲染
9. 安全
-
用户提供的 URL 永远需要通过后端在入库之前进行过滤.需要对该 URL 进行“过滤”以防止通过
javascript:
来执行 JavaScript -
Vue 要在模板内避免渲染 style 标签,避免用户伪造样式,推荐在style属性中使用对象语法,提供特定property值
-
向后端提供 CSRF token 为每个表单生成一个唯一的随机令牌,并要求客户端在提交表单时也附带这个令牌。
10. axios
封装步骤
-
设置接口请求前缀
利用
node
环境变量来作判断,用来区分开发、测试、生产环境if (process.env.NODE_ENV === 'development') {axios.defaults.baseURL = 'http://dev.xxx.com' } else if (process.env.NODE_ENV === 'production') {axios.defaults.baseURL = 'http://prod.xxx.com' }
-
跨域
在本地调试的时候,还需要在
vue.config.js
文件中配置devServer
实现代理转发,从而实现跨域devServer: {proxy: {'/proxyApi': {target: 'http://dev.xxx.com',changeOrigin: true,pathRewrite: {'/proxyApi': ''}}}}
-
设置请求头与超时时间
-
大部分情况下,请求头都是固定的,只有少部分情况下,会需要一些特殊的请求头,这里将普适性的请求头作为基础配置。当需要特殊请求头时,将特殊请求头作为参数传入,覆盖基础配置
const service = axios.create({...timeout: 30000, // 请求 30s 超时headers: {get: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'// 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来},post: {'Content-Type': 'application/json;charset=utf-8'// 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来}}, })
-
-
封装请求方法
先引入封装好的方法,在要调用的接口重新封装成一个方法暴露出去
// get 请求 export function httpGet({url,params = {} }) {return new Promise((resolve, reject) => {axios.get(url, {params}).then((res) => {resolve(res.data)}).catch(err => {reject(err)})}) }// post // post请求 export function httpPost({url,data = {},params = {} }) {return new Promise((resolve, reject) => {axios({url,method: 'post',transformRequest: [function (data) {let ret = ''for (let it in data) {ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'}return ret}],// 发送的数据data,// url参数params}).then(res => {resolve(res.data)})}) }
-
把封装的方法放在一个
api.js
文件中import { httpGet, httpPost } from './http' export const getorglist = (params = {}) => httpGet({ url: 'apps/api/org/list', params })
页面中就能直接调用
// .vue import { getorglist } from '@/assets/js/api'getorglist({ id: 200 }).then(res => {console.log(res) })
这样可以把
api
统一管理起来,以后维护修改只需要在api.js
文件操作即可 -
请求拦截器
请求拦截器可以在每个请求里加上token,做了统一处理后维护起来也方便
// 请求拦截器 axios.interceptors.request.use(config => {// 每次发送请求之前判断是否存在token// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况,此处token一般是用户完成登录后储存到localstorage里的token && (config.headers.Authorization = token)return config},error => {return Promise.error(error)})
-
响应拦截器
响应拦截器可以在接收到响应后先做一层操作,如根据状态码判断登录状态、授权
// 响应拦截器 axios.interceptors.response.use(response => {// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据// 否则的话抛出错误if (response.status === 200) {if (response.data.code === 511) {// 未授权调取授权接口} else if (response.data.code === 510) {// 未登录跳转登录页} else {return Promise.resolve(response)}} else {return Promise.reject(response)} }, error => {// 我们可以在这里对异常状态作统一处理if (error.response.status) {// 处理请求失败的情况// 对不同返回码对相应处理return Promise.reject(error.response)} })
深入响应式原理 vue最独特的特性之一
-
Vue 遍历data中数据对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更
这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
不能检测数组和对象的变化,,而Vue3中的proxy代理解决了这个问题
-
每个组件实例都对应一个 watcher
-
windows事件直接赋给变量,不是响应式,需要在onMounted事件中进行监听
面试题
1. 首屏加载
-
首屏加载是用户体验中最重要的缓解
常见spa首屏优化方案
-
减小入口文件体积
路由懒加载
-
静态资源本地缓存
后端返回资源问题:
-
采用
HTTP
缓存,设置Cache-Control
,Last-Modified
,Etag
等响应头 -
采用
Service Worker
离线缓存
前端合理利用
localStorage
-
-
ui框架按需加载
-
element 按需加载
-
-
组件重复打包
假设
A.js
文件是一个常用的库,现在有多个路由使用了A.js
文件,这就造成了重复下载解决方案:在
webpack
的config
文件中,修改CommonsChunkPlugin
的配置minChunks: 3
minChunks
为3表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件 -
图片资源压缩
对于所有的图片资源,我们可以进行适当的压缩
-
开启GZip压缩
-
使用SSR
SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
从头搭建一个服务端渲染是很复杂的,
vue
应用建议使用Nuxt.js
实现服务端渲染
2. 组件通讯
小型-Vue.observable
步骤
-
创建一个js文件
// 引入vue import Vue from 'vue // 创建state对象,使用observable让state对象可响应 export let state = Vue.observable({name: '张三','age': 38 }) // 创建对应的方法 export let mutations = {changeName(name) {state.name = name},setAge(age) {state.age = age} }
-
在.vue文件中直接使用即可
<template><div>姓名:{{ name }}年龄:{{ age }}<button @click="changeName('李四')">改变姓名</button><button @click="setAge(18)">改变年龄</button></div> </template> import { state, mutations } from '@/store export default {// 在计算属性中拿到值computed: {name() {return state.name},age() {return state.age}},// 调用mutations里面的方法,更新数据methods: {changeName: mutations.changeName,setAge: mutations.setAge} }
3. Promise
-
promise 异步编程解决方案
3.1 以往
-
多层异步操作
doSomething(function(result) {doSomethingElse(result, function(newResult) {doThirdThing(newResult, function(finalResult) {console.log('得到最终结果: ' + finalResult);}, failureCallback);}, failureCallback); }, failureCallback);
-
典型的回调地狱(callback hell)示例。在这种情况下,多个异步操作依赖于前一个操作的结果,导致代码的嵌套层级变得很深,从而降低了可读性和可维护性
3.2 使用promise
doSomething().then(function(result) {return doSomethingElse(result); }) .then(function(newResult) {return doThirdThing(newResult); }) .then(function(finalResult) {console.log('得到最终结果: ' + finalResult); }) .catch(failureCallback);
-
链式操作减低了编码难度
-
代码可读性明显增强
3.3 promise
3.3.1 状态
promise
对象仅有三种状态
-
pending
(进行中) -
fulfilled
(已成功) -
rejected
(已失败)
3.3.2 特点
-
对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态
-
一旦状态改变(从
pending
变为fulfilled
和从pending
变为rejected
),就不会再变,任何时候都可以得到这个结果
3.3.3 流程
3.3.4 用法
-
promise为构造函数
const promise = new Promise(function(resolve, reject) {});
-
Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是
resolve和
reject-
resolve
函数的作用是,将Promise
对象的状态从“未完成”变为“成功” -
reject
函数的作用是,将Promise
对象的状态从“未完成”变为“失败”
-
3.3.5 实例方法
promise .then() .catch() .finally()
-
Promise
对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止 -
Promise对象抛出的错误不会传递到外层代码,即不会有任何反应
-
finally()
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
3.3.6 使用方法
-
Promise
对象抛出的错误不会传递到外层代码,即不会有任何反应
const someAsyncThing = function() {return new Promise(function(resolve, reject) {// 下面一行会报错,因为x没有声明resolve(x + 2);}); };
-
通过
all()
实现多个请求合并在一起,汇总所有请求结果,只需设置一个loading
即可
3.3.7 案例
-
异步插入500w条数据
const {v4: uuidv4} = require("uuid"); const User = require('./models/user') const logger = require('../logger/logger') const getRequestData = require('./data-generator');/*** 异步插入500w条数据*/(async function ormInsert() {try {await User.sync(); // 确保表结构已创建const batchPromises = [];for (let i = 0; i < 10; i++) {batchPromises.push((async () => {const dataList = getRequestData(25);await User.bulkCreate(dataList, { ignoreDuplicates: true });})());}await Promise.all(batchPromises);} catch (error) {logger.error('Error inserting data:', error);} })()
-
通过
race
可以设置图片请求超时面试官:你是怎么理解ES6中 Promise的?使用场景? | web前端面试 - 面试官系列
3.4 async/await与promise关系
-
async/await
和Promise
是 JavaScript 中用于处理异步操作的两种相关机制。 -
async
函数始终返回一个Promise
,而在async
函数内部,可以使用await
关键字来等待一个Promise
完成。 -
async/await
是对Promise
的语法糖,它使得处理异步操作的代码看起来更像是同步代码 -
使用
await
关键字可以避免嵌套的回调函数,使代码结构更清晰。
// 使用 Promise fetchData().then(data => process(data)).then(result => display(result)).catch(error => handleError(error));// 使用 async/await async function main() {try {const data = await fetchData();const result = await process(data);display(result);} catch (error) {handleError(error);} }
4. axios源码
4.1 简易版axois
4.1.1 axios({})
-
构建一个axios构造函数,核心代码为request
class Axios {constructor() {}request(config) {return new Promise(resolve => {const {url = '', method = 'get', data = {}} = config;// 发送ajax请求const xhr = new XMLHttpRequest();// XMLHttpRequest的方法,onload为异步,所以设置在send发出之前异步接收成功的结果xhr.open(method, url, true);xhr.onload = function() {console.log(xhr.responseText)resolve(xhr.responseText);}xhr.send(data);})} }
-
导出axios实例
//最终导出的axios方法,即实例的request方法 function CreateAxiosFn(){ let axios = new Axios(); //使用bind()方法创建一个新的函数,这个函数是axios.request的绑定版本,这样做的目的是确保在调用req时,this上下文是中指向axios实例 return axios.request.bind(axios) }
4.1.2 axios.method()
//定义包含常见HTTP方法的数组get,post...,挂载到Axios原型上 const methodsArr = ['get','delete','head','options','put','patch','post']; //遍历方法数组 methodArr.forEach(met => {Axios.prototype[met] = function() {console.log('执行'+met+'方法')if(['get', 'delete', 'head', 'options'].includes(met)){return this.request({method:met;url:arguments[0],...arguments[1] || {} })}else{//post、put、patch 等方法return this.request({method:met,url:arguments[0],data:arguments[1] || {}...arguments[2] || {}})}} })
4.1.3 this指向
-
肥肠关键
//最终导出的axios方法,即实例的request方法 function CreateAxiosFn(){ let axios = new Axios(); //使用bind()方法创建一个新的函数,这个函数是axios.request的绑定版本,这样做的目的是确保在调用req时,this上下文是中指向axios实例 return axios.request.bind(axios) }
-
then
将Axios.prototype 上的方法搬运到request上
创建工具
const utils = { // 定义一个包含工具方法的对象extend(a, b, context) { // 定义 extend 方法,接收目标对象 a、源对象 b 和上下文对象 contextfor (let key in b) { // 遍历源对象 b 的所有可枚举属性if (b.hasOwnProperty(key)) { // 确保属性是源对象 b 自身的属性if (typeof b[key] === 'function') { // 判断属性值是否是函数a[key] = b[key].bind(context); // 将函数绑定到指定上下文 context,并赋值给目标对象 a} else { // 如果属性不是函数a[key] = b[key]; // 直接将属性值复制到目标对象 a}}}} };
-
修改导出的方法
function CreateAxiosFn() {let axios = new Axios();let req = axios.request.bind(axios);// 增加代码utils.extend(req, Axios.prototype, axios)return req; }
4.1.4 构造拦截器
1. 构造函数
class InterceptorsManage { // 定义一个名为 InterceptorsManage 的类constructor() { // 构造函数,用于初始化类的实例this.handlers = []; // 初始化一个空数组,用于存储拦截器处理函数}use(fullfield, rejected) { // 定义 use 方法,用于添加新的拦截器this.handlers.push({ // 将新的拦截器对象添加到 handlers 数组中fullfield, // 添加成功处理函数rejected // 添加失败处理函数});} }
-
通过使用数组,Axios 能够支持添加多个请求拦截器。这意味着用户可以定义多个函数,每个函数可以在请求发送之前处理请求配置。这样设计可以使得不同的拦截器可以分别处理不同的逻辑,例如:
-
一个拦截器用于添加授权信息。
-
另一个拦截器用于记录请求日志。
-
还有一个拦截器可以用于请求参数的序列化。
-
2. 实现axios.interceptors.response.use和axios.interceptors.request.use
//会在构造函数事,interceptor时初始化一个构造函数
class Axios {constructor() {// 新增代码this.interceptors = {request: new InterceptorsManage,response: new InterceptorsManage}}request(config) {...} }
4.1.5 搬到request
function CreateAxiosFn() { // 定义一个名为 CreateAxiosFn 的函数let axios = new Axios(); // 创建一个 Axios 类的实例并赋值给 axioslet req = axios.request.bind(axios); // 绑定 axios 的 request 方法到 req,确保 this 指向 axios 实例// 混入方法,处理 axios 的 request 方法,使之拥有 get、post 等方法utils.extend(req, Axios.prototype, axios); // 将 Axios 原型上的方法混入 req,确保可以通过 req 调用这些方法// 新增代码utils.extend(req, axios); // 将 axios 实例的方法和属性混入 req,确保 req 也能访问 axios 实例的属性return req; // 返回混合后的 req,作为最终的 axios 方法 }
4.1.6 拦截器执行顺序
-
首先将执行
ajax
的请求封装成一个方法
request(config) {this.sendAjax(config) } sendAjax(config){return new Promise(resolve => {const {url = '', method = 'get', data = {}} = config;// 发送ajax请求console.log(config);const xhr = new XMLHttpRequest();xhr.open(method, url, true);xhr.onload = function() {console.log(xhr.responseText)resolve(xhr.responseText);};xhr.send(data);}) }
-
获得
handlers
中的回调request(config) {// 拦截器和请求组装队列let chain = [this.sendAjax.bind(this), undefined] // 成对出现的,失败回调暂时不处理// 请求拦截this.interceptors.request.handlers.forEach(interceptor => {chain.unshift(interceptor.fullfield, interceptor.rejected)})// 响应拦截this.interceptors.response.handlers.forEach(interceptor => {chain.push(interceptor.fullfield, interceptor.rejected)})// 执行队列,每次执行一对,并给promise赋最新的值let promise = Promise.resolve(config);while(chain.length > 0) {promise = promise.then(chain.shift(), chain.shift())}return promise; }
4.2 源码分析
4.2.1 目录
面试官:你了解axios的原理吗?有看过它的源码吗? | web前端面试 - 面试官系列
5. 权限管理
有空改一下class-select
6. 前端解决跨域
6.1 同源策略
-
协议相同(protocol)
-
主机相同(host)
-
端口相同(port)
6.2 解决方式
6.2.1 JSONP
-
vue中不主要
6.2.2 CORS
-
CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应
-
CORS
实现起来非常方便,只需要增加一些HTTP
头,让服务器能声明允许的访问来源只要后端实现了
CORS
,就实现了跨域 -
前端在 HTTP 头配置 CORS 是无效的,CORS(跨域资源共享,Cross-Origin Resource Sharing)的机制主要依赖于服务器端的配置。浏览器基于同源策略,会自动检查服务器是否允许跨域请求。因此,如果后端没有正确配置 CORS,前端自己设置 HTTP 头并不能绕过浏览器的跨域限制。
-
具体来说,以下是一些关键的响应头,必须由后端设置:
-
Access-Control-Allow-Origin
:指定允许访问的域名,或者使用*
表示允许所有域名。 -
Access-Control-Allow-Methods
:指定允许的 HTTP 方法(如 GET、POST、PUT、DELETE 等)。 -
Access-Control-Allow-Headers
:指定允许的自定义请求头。 -
Access-Control-Allow-Credentials
:如果需要发送凭证(如 Cookies),还需要设置此项为true
。
-
6.2.3 Proxy
-
开发环境可以,生产环境不行
-
无论如何,需要后端配置
7. history模式下有问题404
this
从头创建vue2 项目
1. 步骤
-
安装vue cli
npm install -g @vue/cli
-
创建新项目
vue create yhs-web
-
选择特性
2. 网络监听
构建工具
1. vue-cli
2. webpack
-
当你使用命令
vue create my-project
创建一个 Vue 项目时,Vue CLI 会自动生成一个项目结构,并且会包含默认的 Webpack 配置。这些配置用于开发、构建、打包应用。
2.1 配置
-
Vue CLI 内部集成了 Webpack 并提供了预配置好的 Webpack 配置。通常在 Vue CLI 项目中,你不需要手动修改 Webpack 配置,Vue CLI 会在开发和生产模式下自动处理以下内容:
-
处理单文件组件(
.vue
文件)。 -
处理 JavaScript、CSS、图像等静态资源的打包。
-
提供热更新(Hot Module Replacement, HMR)功能来提高开发体验。
-
通过
webpack-dev-server
提供本地开发服务器。
-
-
当你在开发环境下运行
npm run serve
或yarn serve
,Vue CLI 会:-
调用 Webpack 配置,启动
webpack-dev-server
。 -
Webpack 负责编译、打包代码,并在本地服务器上提供应用。
当你在生产环境下运行
npm run build
或yarn build
时,Vue CLI 会:-
调用 Webpack,进行代码的优化和压缩。
-
将最终的应用程序打包输出到
dist/
目录中。
-
-
可选配置
虽然 Vue CLI 提供了默认的 Webpack 配置,但它也允许开发者通过
vue.config.js
文件自定义 Webpack 配置。你可以在vue.config.js
文件中对 Webpack 进行扩展、修改,比如:-
修改别名(alias)
-
添加插件
-
更改打包规则(loaders)
-
2.2 案例
-
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({devServer: {host: '0.0.0.0', // 绑定到所有网络接口port: 8081, // 设置端口号open: false, // 自动打开浏览器},transpileDependencies: true })
-
使用了
defineConfig
,用于指定 Vue CLI 的配置。 -
devServer
的配置:-
host: '0.0.0.0'
:将开发服务器绑定到所有网络接口,意味着可以从本地局域网中的其他设备访问该服务器。 -
port: 8081
:将开发服务器的端口设置为8081
(默认是8080
)。 -
open: false
:禁用了自动打开浏览器的功能。
-
-
-
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({lintOnSave: false,transpileDependencies: true// devServer:{// //devServe在发送请求时,会先走道before指定的函数中进行处理,如果before中没有对应的移动路由,才会请求外网// setupMiddlewares:require('./src/mock/index')// } })
-
禁用了
lintOnSave
(保存时的 ESLint 检查) -
transpileDependencies
配置为了确保通过 Babel 转译依赖项以提高兼容性。 -
注释掉了开发服务器的中间件配置,可能用于本地模拟数据。
-
setupMiddlewares
指定了中间件处理函数,路径指向./src/mock/index
,这表明项目可能使用了一个本地的模拟数据服务器,用来处理请求。如果注释去掉,它将通过自定义的中间件处理请求(如使用 mock 数据),只有当该中间件无法处理请求时,才会请求外部 API。
-
-
2.3 正确示例
-
Webpack 需要通过
entry
、output
、rules
和plugins
来进行大量配置,尤其在处理不同类型的资源(如 JS、CSS、图片等)时需要加载不同的loader
。
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, 'dist'),},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: 'babel-loader',},{test: /\.css$/,use: ['style-loader', 'css-loader'],},],},plugins: [new HtmlWebpackPlugin({template: './src/index.html',}),],devServer: {contentBase: './dist',hot: true,}, };
3. vite
3.1 与webpack区别
3.1.1 webpack
Webpack 是一个基于打包(bundling)的工具,主要通过以下步骤工作:
-
静态分析依赖关系:Webpack 从入口文件(如
src/index.js
)开始,递归地构建依赖图,将项目中所有的模块(包括 JS、CSS、图片等)都打包成一个或多个文件。 -
打包和优化:Webpack 会将所有依赖打包成少量的文件(通常是
bundle.js
),并应用一些优化策略(如代码分割、压缩、Tree Shaking 等)。 -
开发模式和热更新:Webpack 开发时会启动
webpack-dev-server
,它会将代码加载到内存中,并支持热模块替换(HMR),当源代码发生变化时,只更新变化的部分模块,而不是刷新整个页面
3.1.2 vite
Vite 的主要目标是提高开发效率,特别是在大型项目中。它采用了一种与 Webpack 不同的工作方式:
-
即时启动(Instant Server Start):Vite 使用原生 ES 模块(ESM)支持的浏览器来直接加载 JavaScript 文件,而不是像 Webpack 一样打包所有文件。它会根据需要按需加载模块,而不是一次性打包整个项目。
-
模块按需编译:在开发时,Vite 只编译正在使用的模块,而不是打包整个项目。这大大减少了启动时间和内存占用。
-
生产模式下打包:在生产环境中,Vite 仍然使用 Rollup 进行打包(Rollup 和 Webpack 类似,是另一种打包工具),生成优化后的静态资源文件。
3.2 案例
案例1
import path from "path" import { fileURLToPath, URL } from "url"import { defineConfig } from "vite" import vue from "@vitejs/plugin-vue" import { viteSingleFile } from "vite-plugin-singlefile" // 构建配置会根据process.env.LTB来决定是否构建为库 //LIB值定义在语句build-lib,运行该命令设置lib值自动打包为库 const build = process.env.LIB? {lib: {entry: path.resolve(__dirname, "src/components/index.ts"),name: "pev2",fileName: "pev2",},rollupOptions: {external: ["vue"],output: {// Provide global variables to use in the UMD build// Add external deps hereglobals: {vue: "Vue",},},},}: {outDir: "dist-app",target: "esnext",assetsInlineLimit: 100000000,chunkSizeWarningLimit: 100000000,cssCodeSplit: false,brotliSize: false,rollupOptions: {output: {inlineDynamicImports: true,},},}// https://vitejs.dev/config/ export default defineConfig({build: build,plugins: [ //使用了 vue 插件,用于支持 Vue 单文件组件。vue({template: {compilerOptions: {whitespace: "preserve",},},}), //使用 viteSingleFile 插件,将所有资源内联到一个单文件中。viteSingleFile(),], //路径别名resolve: {alias: {"@": fileURLToPath(new URL("./src", import.meta.url)),},},define: { //定义了 __APP_VERSION__ 来读取 package.json 中的版本号__APP_VERSION__: JSON.stringify(process.env.npm_package_version), //定义了 process.env.NODE_ENV 以便根据环境切换配置。"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),}, })
-
根据LIB值决定构建模式
-
当
process.env.LIB
为true
时:构建为库lib
:-
entry
: 指定库的入口文件为src/components/index.ts
,这是库的主要导出文件。 -
name
: 定义库的名称为pev2
,这个名称会在 UMD(Universal Module Definition)构建中使用。 -
fileName
: 定义输出文件的名称为pev2
。
rollupOptions
:-
external
: 指定外部依赖vue
,意味着在打包时 Vue 不会被包含在输出文件中,而是期望在运行时通过全局变量Vue
提供。 -
output
:
-
globals
: 定义 UMD 构建时的全局变量,用于引用外部依赖。在这里,vue
被指定为全局变量Vue
,这使得使用这个库的应用能够在全局上下文中访问 Vue。
-
-
-
当
process.env.LIB
不存在或为false
时:构建为普通应用outDir
: 指定构建输出目录为dist-app
,构建结果会输出到这个目录下。target
: 指定构建目标为esnext
,表示构建输出将使用最新的 ECMAScript 语法特性。assetsInlineLimit
: 设置资产内联的限制,这里设定为一个非常大的值(100000000),意味着几乎所有的资源(如小于这个大小的图像、CSS 文件等)都会被内联。chunkSizeWarningLimit
: 设定 chunk 大小警告的限制,设置为一个非常大的值以避免在构建时收到 chunk 大小的警告。cssCodeSplit
: 设置为false
,表示禁用 CSS 代码分割,所有的 CSS 会被打包成一个文件。brotliSize
: 设置为false
,表示不计算 Brotli 压缩的大小。rollupOptions
:-
output
:
-
inlineDynamicImports
: 设置为true
,表示所有动态导入的模块都将内联到单个输出文件中,而不是生成多个分离的 chunk。
-
-
-
-
构建配置
-
根据build决定是否构建为库
-
使用vue插件用于支持vue单文件组件
-
-
全局常量
-
__APP_VERSION__
:-
这个常量被定义为当前项目的版本号,它是从
package.json
文件中读取的version
字段(通过process.env.npm_package_version
)。 -
通过
JSON.stringify
处理后,它会转换为一个字符串,这样在应用中可以直接引用,例如:
javascript复制代码 console.log(__APP_VERSION__); // 输出项目的版本号
-
这对于版本管理、调试和在 UI 中展示版本号很有用。
-
-
process.env.NODE_ENV
:-
这个常量代表当前的运行环境(如开发、生产或测试)。通常在开发工具链中,这个值会被设置为
development
或production
。-
通过
JSON.stringify
处理后,引用时会是一个字符串。例如:
javascript复制代码if (process.env.NODE_ENV === 'production') {// 执行生产环境特定的代码 }
-
-
使用
NODE_ENV
变量的好处是可以在代码中根据不同的环境执行不同的逻辑,比如启用调试工具、日志记录等。
-
-
全局常量
-
可以配置的地方
-
vite define
-
-
根实例中
// main.js import { createApp } from 'vue'; import App from './App.vue';const app = createApp(App); // 获取版本号 const APP_VERSION = process.env.npm_package_version; // 访问环境变量 const NODE_ENV = process.env.NODE_ENV || 'development'; // 获取当前环境变量app.provide('appVersion', __APP_VERSION__); app.provide('env', process.env.NODE_ENV);app.mount('#app');
组件中可以使用this.appVersion
-
使用vuex
// store.js import { createStore } from 'vuex';const store = createStore({state: {appVersion: __APP_VERSION__,env: process.env.NODE_ENV,}, });export default store;
-
在环境变量文件中设置
# .env VITE_APP_VERSION=1.0.0
在组件中访问
console.log(import.meta.env.VITE_APP_VERSION); // 访问环境变量
案例2
import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' import Icons from 'unplugin-icons/vite' import IconsResolver from 'unplugin-icons/resolver' // https://vitejs.dev/config/ export default defineConfig({plugins: [ //支持vue单文件组件vue(),AutoImport({resolvers: [ElementPlusResolver(),// 自动导入图标组件IconsResolver({prefix: 'Icon',}),],}),Components({resolvers: [ElementPlusResolver(),// 自动注册图标组件IconsResolver({enabledCollections: ['ep'],}),],}),Icons({autoInstall: true,}), ],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url)),"@/ts": "./src/*.ts","@/tsDeep": "./src/**/*.ts"}} })
差异
-
第一个项目使用了
viteSingleFile
,使其可以将项目打包成一个单文件,适合需要在某些特殊场景下进行部署的项目。 -
第二个项目更加专注于提高开发体验,使用了自动导入、组件自动注册和图标插件,特别适合使用
Element Plus
UI 框架的项目。 -
全局变量:第一个项目有更多针对版本号和环境的全局变量定义,而第二个项目没有这方面的配置。
3.3 正确示例
-
Vite 的配置相对简洁,因为 Vite 默认支持现代浏览器的 ESM 规范,很多复杂的配置(如模块加载、热更新)都是开箱即用的,开发服务器和打包的配置都很简洁。
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({plugins: [vue()],server: {host: '0.0.0.0',port: 3000,open: true, // 启动时自动打开浏览器},build: {outDir: 'dist', // 打包输出目录}, });
TS
1. tsconfig.json配置
GIT
-
更换仓库
-
更改远程仓库地址
git remote set-url origin 新地址 git remote set-url origin git@github.com:DHWhale01/yhs-web.git https://gitee.com/code-ql/yhs-web.git
-
正常提交就可以了
相关文章:

深入Vue2
frontend Vue2 学习内容参考 /在线运行 Element 学习内容参考 /视频教学 vue2 1. vue 实例 当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中 但是当使用Object.freeze(),会阻止修改现有的 property&#x…...

opencv-rust 系列3: Create_mask
前言: 这里只是opencv-rust自带示例的中文注解. 略微增加了一些代码也是我在调试时用到的. 调试方法可参见前文. 一. 这个程序还是有点难度的, 关键点在于: 创建了遮罩. 直接调用一个函数, 还是很简单的.窗口事件处理. 注册窗口回调函数, 用以处理鼠标事件进程同步和互斥锁. 为…...

Go语言初识
一、Go语言概述 Go语言是为了取代C和java的地位,既要保留C的简洁,也追求java的规模化开发 并行及分布式的支持,使得开发多核及多机器集群程序如同单机一样简单 Go语言从语言级别支持协程(goroutine, 轻量级线程),Go语言…...

Android Activity SingleTop启动模式使用场景
通知栏 当用户点击通知栏中的通知时,可以使用单顶启动模式来打开对应的活动,并确保只有一个实例存在。 简单集成极光推送 创建应用 获取appkey参数 切换到极光工作台 极光sdk集成 Project 根目录的主 gradle 配置 Module 的 gradle 配置 Jpush依赖配置 配置推送必须…...

PHP 代码执行相关函数
函数 说明 示例代码 ${} 用于复杂的变量解析,通常在字符串内用来解析变量或表达式。可以配合 eval 或其他动态执行代码的功能,用于间接执行代码。 eval(${flag}); eval() 用于执行一个字符串作为 PHP 代码。可以执行任何有效的 PHP 代码片段。没有…...

五周年,继续破浪前行
五周年,TapData 再一次带着自己的“乘风破浪”大队,在一个阳光明媚的日子里,把生日过在了海上。 头顶日升日落,这条属于全体 Tap-pers 的航船,再次校准航向,在船长的带领下,驶向下一个晴好的明…...

【操作系统】Linux之进程管理一
第1关:获取进程常见属性 ret.pidgetpid(); ret.ppidgetppid(); 第2关:进程创建操作-fork pid_t pid fork(); if(pid-1) printf("创建进程失败!"); else if(pid0) printf("Children"); else printf("Parent"); …...

C语言_数据在内存中的存储
1. 整数在内存中的存储 计算机中的整数有三种2进制表示方法 :原码、反码、补码。 三种表示方式均有符号位和数值位两个部分,最高一位的是符号位,剩下的都是数值位。符号位用“0”表示“正”,用“1”表示“负”。 正数的原、反、…...

华为原生鸿蒙操作系统:我国移动操作系统的新篇章
华为原生鸿蒙操作系统:我国移动操作系统的新篇章 引言 在移动操作系统领域,苹果iOS和安卓系统一直占据主导地位。然而,随着华为原生鸿蒙操作系统的正式发布,这一格局正在发生深刻变化。作为继苹果iOS和安卓系统后的全球第三大移动…...

队列的基本操作(数据结构)
1.实验内容: 编写一个程序sqqueue.cpp,实现环形队列(假设栈中元素类型ElemType 为 char)的各种基本运算,并在此基础上设计一个程序exp4_1.cpp,完成如下功能: 2.实验步骤: (1)初始化队列q (2)判断队列q是否非空 (3…...

linux开机自启动三种方式
方式一、 1:rc.local 文件 1、执行命令:编辑 “/etc/rc.local” vi /ect/rc.local 2、然后在文件最后一行添加要执行程序的全路径。 例如,每次开机时要执行一个 hello.sh,这个脚本放在 / usr 下面,那就可以在 “/et…...

AI创作者与人类创作者的协作模式
公主请阅 1. AI创作者的崛起1.1 AI创作者的工作原理1.2 AI创作者的优势 2. 人类创作者的独特价值2.1 创造性与情感2.2 伦理与价值观2.3 文化与背景 3. AI与人类的协作模式3.1 协同创作3.2 内容编辑3.3 数据驱动的创作3.4 跨媒体协作 4. AI与人类协作的挑战4.1 技术局限性4.2 版…...

FPGA第 13 篇,使用 Xilinx Vivado 创建项目,点亮 LED 灯,Vivado 的基本使用(点亮ZYNQ-7010开发板的LED灯)
前言 在FPGA设计中,Xilinx Vivado软件是一款功能强大的设计工具,它不仅支持硬件描述语言(HDL)的开发,还提供了丰富的图形化设计界面,方便用户进行硬件设计、调试和测试。这里我们将详细介绍,如…...

Kafka文档阅读笔记之基本操作
官方资料 官方首页官方文档基本操作topic的配置参数 topic的部分操作 创建新的topic 命令样例,如下: bin/kafka-topics.sh \--bootstrap-server localhost:9092 \--create \--topic my_topic_name \--partitions 20 \--replication-factor 3 \--conf…...

Golang | Leetcode Golang题解之第506题相对名次
题目: 题解: var desc [3]string{"Gold Medal", "Silver Medal", "Bronze Medal"}func findRelativeRanks(score []int) []string {n : len(score)type pair struct{ score, idx int }arr : make([]pair, n)for i, s : …...

机器学习——元学习(Meta-learning)
元学习(Meta-learning):学习如何学习的机器学习 元学习(Meta-learning),即“学习如何学习”,是机器学习领域中一个令人兴奋且极具潜力的研究方向。它的核心目标是让机器学习系统学会高效地学习…...

【TIMM库】是一个专门为PyTorch用户设计的图像模型库 python库
TIMM库 1、引言:遇见TIMM2、初识TIMM:安装与基本结构3、实战案例一:图像分类4、实战案例二:迁移学习5、实战案例三:模型可视化6、结语:TIMM的无限可能 1、引言:遇见TIMM 大家好,我是…...

【AIGC】从CoT到BoT:AGI推理能力提升24%的技术变革如何驱动ChatGPT未来发展
博客主页: [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯迈向AGI的新跨越💯BoT与CoT的技术对比技术原理差异推理性能提升应用范围和通用性从错误中学习的能力总结 💯BoT的工作流程和机制初始化过程生成推…...

若依部署上线遇到的问题
一、若依部署上线的用户头像模块不能回显: 首先是后端修改部署上线后若依存储图片的本地地址 其次将上线前端配置文件中的图片相关配置给删除 二、若依部署上线后验证码不显示问题 在确保前后端请求打通后还有这个问题就是磁盘缓存问题 三、若依部署上线遇到404页…...

一个vue3的待办列表组件
一个vue3的待办列表组件, 仿企业微信的待办列表 TodoList.vue <template><div><el-input v-model"todoInput" placeholder"写下你的待办事项..." class"el-input" keyup.enter"addTodo"input-style"background-c…...

深入分析梧桐数据库SQL查询之挖掘季度销售冠军
在现代商业环境中,对销售数据的深入分析是企业决策过程中不可或缺的一部分。通过分析销售数据,企业可以识别出表现最佳的员工,从而激励团队,优化销售策略,并提高整体业绩。本文将详细介绍如何使用SQL查询来识别每个季度…...

「ZJUBCA秋季迎新见面会预告」
01 TIME 主席团与各部部长致辞 Presidents and Leads speech 02 TIME Aptos宣讲 Aptos Pitch-Hackathon 03 TIME 破冰小游戏 Icebreaker Games-Mining a Bitcoin 04 TIME 观影 Movie time! ⬇️浙江大学区块链协会秋季迎新见面会预告⬇️ 01 Presidents and Leads s…...

钉钉消息推送工具类
pom.xml <!-- HuTool 工具 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.12</version></dependency><!-- commons-lang3 --><dependency><groupId>…...

Android Studio 导入/删除/新建库的模块(第三方项目) - Module
文章目录 一、导入module项目 Module空项目如何导入Project工程项目二、删除module项目三、新建module项目(不常用) 一、导入module项目 首先,你必须要有一个工程(Project),才可以打开项目(Module) 第一步骤:右键项目依次点击 New -> Module 1、工…...

flowable 去掉自带的登录权限
重写Security配置,使所有请求都可以通过Security验证。(/**/**) 如: 公共的Security配置 package com.central.workflow.config;import org.springframework.context.annotation.Configuration; import org.springframework.se…...

第T8周:猫狗识别
>- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)** 🍺 要求: 了解mode…...

第十七周:机器学习
目录 摘要 Abstract 一、MCMC 1、马尔科夫链采样 step1 状态设定 step2 转移矩阵 step3 马尔科夫链的生成 step4 概率分布的估计 2、蒙特卡洛方法 step1 由一个分布产生随机变量 step2 用这些随机变量做实验 3、MCMC算法 4、参考文章 二、flow-based GAN 1、引…...

算法4之链表
概述 链表的题目没有太难的算法,纯看熟练度,是必须会。面试笔试不会是直接挂的,或者给面试官留下不好的印象。 单双链表的反转,单链表实现队列,K个一组反转链表。 单链表反转 链表节点的定义 Data public class Li…...

掌握未来技术:KVM虚拟化安装全攻略,开启高效云端之旅
作者简介:我是团团儿,是一名专注于云计算领域的专业创作者,感谢大家的关注 座右铭: 云端筑梦,数据为翼,探索无限可能,引领云计算新纪元 个人主页:团儿.-CSDN博客 目录 前言&#…...

挖矿病毒的处理
前阶段生产服务器又中挖矿病毒了,紧急处理了一波 现象 执行 top命令,查看哪里cpu占用较高 CPU 彪满下不来 解决 1、杀掉进程 kill -9 pid 2、但是,过一会又不行了,说明有定时任务在定时执行这个病毒 3、先找到病毒文件&…...