跳槽是每个人的职业生涯中都要经历的过程,不论你是搜索到的这篇文章还是无意中浏览到的这篇文章,希望你没有白白浪费停留在这里的时间,能给你接下来或者以后的笔试面试带来一些帮助。
也许是互联网未来10年中最好的一年。WINTER IS COMING。但是如果你不真正的自己去尝试尝试,你永远不知道市面上的行情如何。这次找工作下来,我自身感觉市场并没有那么可怕,也拿到了几个大厂的offer。在此进行一个总结,给自己,也希望能帮助到需要的同学。
面试准备
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
面试准备根据每个人掌握的知识不同,准备的时间也不一样。现在对于前端岗位,以前也许不是很重视算法这块,但是现在很多公司也都会考。建议大家平时有空的时候多刷刷leetcode。算法的准备时间比较长,是一个长期的过程。需要在掌握了大部分前端基础知识的情况下,再有针对性的去复习算法。面试的时候算法能做出来肯定加分,但做不出来也不会一票否决,面试官也会给你提供一些思路。
主页
### 6` 接口 泛型 自定义类型
person.ts
//1. 定义一个接口 用于限制person对象的具体属性
export interface Person{
id:string,
name:string,
age:number
}
//2. 一个自定义类型
//数组 方法一
// export type Persons = Array
//数组 方法二
export type Persons = Person[]
Person.vue
### 7` props的使用
#### 简单示例:
接收父类传过来的数据 defineProps([' '])
父类内容:
```
子类引用:
<script setup lang="ts" name="Person">
defineProps(['a'])
</script>
<template>
{{ a }}
</template>
曾加难度:
接收数组
父类内容:
<script setup lang="ts">
import Person from "@/components/Person.vue";
import {type Persons} from '@/typedefine/person'
import {reactive} from "vue";
//定义数组数据
let persionList= reactive<Persons>([
//let定义 persion名称 :Array数组 <person>泛型
{id: '01', name: 'LiM', age: 19},
{id: '02', name: 'Li', age: 18},
{id: '03', name: 'L', age: 19}
])
console.log(persionList)
</script>
<template>
<person a="哈哈哈哈" :list="persionList"/>
</template>
<style scoped>
</style>
子类内容:
<script setup lang="ts" name="Person">
import type {Persons} from "@/typedefine/person";
// //只接收list
// defineProps(['list'])
// //接收list + 限制类型
// defineProps<{ list: Persons }>()
// //接收list + 限制类型 + 限制必要性
// defineProps<{ list?: Persons }>()
//接收list + 限制类型 + 限制必要性 + 指定默认值
withDefaults(defineProps<{ list?: Persons }>(), {
list: () => [{id: '00', name: '0号', age: 20}]
})
// //接收list 同时将props保存起来
// let x = defineProps(['list'])
</script>
<template>
<div class="person">
<ul>
<li v-for="persionObj in list" :key="persionObj.id">
{{ persionObj.name }} -- {{ persionObj.age }}
</li>
</ul>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
8` 生命周期
概念:Vue组件实例在创建时要经历一系列的初始化步骤,在此过程中Vue会在合适的时机, 调用特定的函数, 从而让开发者有机会在特定阶段运行自己的代码, 这些特定的函数统称为: 生命周期钩子
注意:
当引用组件时 子组件会优先于父组件进行挂载
用 v-if 来决定是否显示时 如果条件为false那么内容将会被销毁
用v-show来决定是否显示时 如果条件为false那么内容会被隐藏
8.1 Vue2生命周期
组件的生命周期: 四个周期 八个钩子
[时刻] [调用特定函数]
–>创建(创建前 beforeCreate, 创建完毕 created)
–>挂载(创建前 beforeMount, 挂载完毕 mounted)
–>更新(创建前 beforeUpdate, 挂载完毕 update)
–>销毁(创建前 beforeDestroy, 销毁完毕 destroyed)
拓展: 用 v-if 来决定是否显示时 如果条件为false那么内容将会被销毁 但是如果用v-show则会隐藏
8.2 Vue3生命周期
组件的生命周期: 四个周期 八个钩子
[时刻] [调用特定函数]
–>创建 setup函数(vue3推荐使用setup语法糖 所以setup都不需要在写了)
–>挂载(创建前 onBeforeMount, 挂载完毕 onMounted)
–>更新(创建前 onBeforeUpdate, 挂载完毕 onUpdate)
–>卸载(创建前 onBeforeUnmount, 销毁完毕 onUnmounted)
拓展: vue3调用函数需要在函数内写上回调函数 ()=>{ 这里面写你要写的东西 }
9`自定义Hooks
hooks 简单来说就是外联ts 把冗杂的ts内容(数据 函数 方法 钩子)单独存放,在需要的时候进行使用
9.1 创建一个文件夹名称为hooks
9.2 创建ts文件
axios 网络请求
安装: npm i axios (控制台)
引入: import axios from ‘axios’ (组件)
useDog.ts
import axios from "axios";
import {reactive} from "vue";
export default function () {
//数据
let dogList = reactive([
'Https://api.dujin.org/pic'
])
//函数
async function getDog() {
try {
let result = await axios.get('Https://api.dujin.org/pic')
dogList.push(result.data.message)
} catch (error) {
alert(error)
}
}
//向外部提供信息
return {dogList,getDog}
}
useSum.ts
import {ref} from "vue";
export default function () {
//数据
let sum = ref(0)
//函数
function changerSum() {
sum.value++
}
return {sum,changerSum}
}
9.3在需要的时候使用
在vue组件内使用
import useSum from "@/hooks/useLoginIn";
const {sum,changerSum} = useSum()
二`路由
路由就是 一组 key 和 value 的对应关系( key + value => route) 多个路由由路由器管理
1.路由的基本切换效果
创建几个vue文件
@/router/index.ts
// 创建一个路由器 ,并暴露出去
//引入
import {createRouter, createWebHistory} from 'vue-router'
// 引入组件
import lable from '@/views/lable.vue'
import logHome from "@/views/log/logHome.vue";
import login from "@/views/log/page/login.vue";
import logon from "@/views/log/page/logon.vue";
import back from "@/views/log/page/back.vue";
// 创建路由
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'lable',
component: () => lable,
// 标签页
}, {
path: '/log',
name: 'log',
component: () => logHome,
// 登录注册页
children: [
{
path: '/log/login',
name: 'login',
component: () => login
// 登录页
}, {
path: '/log/logon',
name: 'logon',
component: () => logon
// 注册页
}, {
path: '/log/back',
name: 'back',
component: () => back
// 找回
},
]
}
]
})
// 暴露路由
export default router
main.ts
// 引入createApp用于创建应用
import { createApp } from 'vue'
// 引入App跟组件
import App from './App.vue'
// 引入路由
import router from './router'
// 使用路由
app.use(router)
// 挂载整个容器到app容器中
app.mount('#app')
vue.页面
<script setup lang="ts" name="Person">
//展示区占位RouterView
import {RouterView,RouterLink} from "vue-router";
</script>
<template>
<div class="person">
<h2>VUE路由测试</h2>
<!-- 导航区-->
<div>
<RouterLink to="/lable" active-class="/logHome">首页</RouterLink>
<!-- active-class="" 激活时展示样式-->
<RouterLink to="/login">登录</RouterLink>
<RouterLink to="/logon">注册</RouterLink>
<RouterLink to="/back">找回</RouterLink>
</div>
<!-- 展示区-->
<div>
展示组件
<RouterView/>
</div>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
2` 路由的两个注意点
1.路由组件通常存放在pages 或者 views文件夹 ,一般组件通常放在 components文件夹
路由组件: 靠路由的规则渲染出来的(不是通过标签展示出来的 比如: 这种的)
一般组件: 是咱们程序员亲手写的那种标签的组件
2.通过点击导航,视觉上"消失"了的路由组件 ,默认是被销毁掉的 ,需要的时候再去挂载
3` to的两种写法
基础写法:
1.字符串写法:登录
2.对象写法: 登录
传参写法:
query写法:
<div>
<!-- 路由传参-->
<ul>
<!-- 方法一-->
<li v-for=" item in newList " :key="item.id">
<RouterLink :to="`/?id=${item.id}&title=${item.title}`">{{ item.title }}</RouterLink>
</li>
<!-- 方法二-->
<li v-for=" item in newList " :key="item.id">
<RouterLink
:to="{
path:'/',
query:{
id:item.id,
title:item.title
}
}">
{{ item.title }}
</RouterLink>
</li>
</ul>
</div>
参数接收
<script setup lang="ts">
let route = useRoute()
let {query} = toRefs(route)
</script>
<template>
<ul>
<li>编号:{{router.id}}</li>
<li>标题:{{router.title}}</li>
</ul>
</template>
params写法:
备注1:传递params参数时 ,若使用to的对象写法,必须使用name配置项,不能用path
备注2:传递params参数时 ,需要提前在规则中占位
vue组件内:
<script setup lang="ts" name="Person">
</script>
<template>
<div class="person">
<h2>VUE路由测试</h2>
<!-- 导航区-->
<div>
<!-- 路由传参-->
<ul>
<!-- 方法一-->
<li v-for=" item in newList " :key="item.id">
<RouterLink :to="`/${item.id}/${item.title}`">{{ item.title }}</RouterLink>
</li>
</ul>
<ul>
<!-- 方法二-->
<li v-for=" item in newList " :key="item.id">
<RouterLink
:to="{
name:"/"
<!--注意因为之前路径用占位了所以这块用name跳转 且不能传对象和数组-->
params:{
id:item.id,
title:item.title
}
}"
>
{{ item.title }}</RouterLink>
</li>
</ul>
</div>
<!-- 展示区-->
<div>
展示组件
<RouterView/>
</div>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
路由文件内:
routes: [
{
path: '/:x/:y?',//:x为必须传的 :y?为可传可不传
name: 'lable',
component: () => lable,
// 标签页
}
]
参数接收
<script setup lang="ts">
let route = useRoute()
let {query} = toRefs(route)
</script>
<template>
<ul>
<li>编号:{{router.params.id}}</li>
<li>标题:{{router.params.title}}</li>
</ul>
</template>
4` 路由器的工作模式
history模式
写法:
vue2: mode:'hsitory
vue3: history:createWebHistory()
React: BrowserRouter 标签
优点:URL更加美观,不带有# ,更接近传统网站的URL
缺点:后期项目上线 ,需要服务端配合处理路径问题 ,否则刷新会有404错误
hash模式
写法:
vue2: mode:'hash
vue3: history:createWebHashHistory()
React: HashRouter 标签
优点:兼容性更好 ,因为不需要服务器端处理路径
缺点:URL带有#不太美观 ,且在SEO优化方面相对较差
`5 路由的props配置
作用:让路由组件更方便的收到参数(可以将路由参数作为 props 传给组件)
路由:
routes: [
{
path: '/:x/:y?',//:x为必须传的 :y?为可传可不传
name: 'lable',
component: () => logHome,//组件地址
// 第一种写法,将路由收到的所有params参数作为props传给路由组件
props:true
// 第二种写法,可以自己决定将什么作为props传给路由组件
// 对象写法
// 比如传query的
// props(route){
// return route.query
// }
}
]
组件:
<script setup lang="ts">
defineProps(['id','title'])
</script>
<template>
<ul>
<li>编号:{{id}}</li>
<li>标题:{title}}</li>
</ul>
</template>
6` replace属性
push: 栈模式 可以 前进 后退(默认)
replace: 覆盖 不能 前进 后退 在
7` 编程试导航
脱离RouterLink实现跳转
路由组件的两个重要的属性: $route 和 $router 变成了两个 hooks
<script setup lang="ts" name="Person">
import {onMounted} from "vue";
import {useRouter} from "vue-router";
//路由器
const router = useRouter()
//组件挂在
onMounted(()=>{
//展示事件
setTimeout(()=>{
//让路由实现跳转
router.push('/')//push跳转 留下历史记录 可以前进 后退
// router.replace('/')//replace跳转 不留记录
},3000)//只能看3s
})
</script>
<template>
<div class="person">
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
8` 路由的重定向
将本来应该跳转到/的跳转到/home那
routes: [
{
path: '/',
name: 'lable',
component: () => lable,
// 标签页
},{
path: '/home',
name: 'home',
component: () => home,
// 标签页
},{
path: '/',
redirect: '/home'
}
]
三` pinia 仓库
Pinia: 集中式状态(数据) 管理
1.搭建环境
下载: npm install pinia
main.ts
// 引入createApp用于创建应用
import {createApp} from 'vue'
//引入App跟组件
import App from './App.vue'
//引入pinia
import {createPinia} from 'pinia'
// 应用路由
const app = createApp(App)
// pinia注入
app.use(createPinia())
// 挂载整个容器到app容器中
app.mount('#app')
2.创建目录
创建一个目录名称为store
3.编写格式
count.ts
// 引入仓库
import {defineStore} from "pinia";
// 使用仓库 官方命名规则: use+文件名+Store
// defineStore参数1: id 推荐与文件名一致
// defineStore参数2: options 配置对象
export const useCountStore = defineStore('count',{
// actions里面放置的是一给个的方法,用于相应组件种的"动作"
actions:{
increment(value){
if(this.sum<10){
console.log('此方法被调用',value)
//修改数据
this.sum+=value
}
}
},
//真正存储数据的地方
state() {
return{
sum:7,
school1:'辽工大',
school2:'辽科大'
}
},
})
Count.vue
<script setup lang="ts" name="count">
import {ref} from "vue";
import {useCountStore} from "@/stores/count";
//数据
let n = ref(1)
//拿到数据并将其存入countStore
const countStore = useCountStore()
//函数
function add() {
countStore.sum+=n.value
console.log(n)
}
</script>
<template>
<div class="person">
<h2>当前求和为: {{ countStore.sum }}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">加</button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
4`修改数据的三种方式:
<script setup lang="ts" name="count">
import {ref} from "vue";
import {useCountStore} from "@/stores/count";
//数据
let n = ref(1)
//拿到数据并将其存入countStore
const countStore = useCountStore()
//函数
function add() {
//第一种修改方式:直接修改
// countStore.sum+=n.value
// countStore.sum = '北大'
// countStore.sum = '清华'
//第二种修改方式:批量修改
// countStore.$patch({
// sum:888,
// school1: '北大',
// school2: '郊大'
// })
//第三种修改方法:调用在count.ts已经定义好了的方法
countStore.increment(n.value)
}
</script>
<template>
<div class="person">
<h2>当前求和为: {{ countStore.sum }}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">加</button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
5` storeToRefs 解构数据
将store内的数据结构出来(只解构其中的数据,不会对方法进行)
<script setup lang="ts" name="count">
import {ref} from "vue";
import {useCountStore} from "@/stores/count";
import {storeToRefs} from "pinia";
//数据
let n = ref(1)
//拿到数据并将其存入countStore
const countStore = useCountStore()
//解构
const {sum,school1,school2} = storeToRefs(countStore)
//函数
function add() {
countStore.increment(n.value)
}
</script>
<template>
<div class="person">
<h2>当前求和为: {{ sum }}</h2>
<h2>{{school1}}</h2>
<h2>{{school2}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">加</button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
6` getters 加工数据
count.ts
// 引入仓库
import {defineStore} from "pinia";
import {state} from "vue-tsc/out/shared";
// 使用仓库 官方命名规则: use+文件名+Store
// defineStore参数1: id 推荐与文件名一致
// defineStore参数2: options 配置对象
export const useCountStore = defineStore('count',{
// actions里面放置的是一给个的方法,用于相应组件种的"动作"
actions:{
increment(value){
if(this.sum<10){
console.log('此方法被调用',value)
//修改数据
this.sum+=value
}
}
},
//真正存储数据的地方
state() {
return{
sum:7,
school1:'辽工大',
school2:'辽科大'
}
},
//加工数据
getters:{
bigSum:state => state.sum*10,
upperSchool():string{
return this.school1+'很好'
}
}
})
Count.vue
<script setup lang="ts" name="count">
import {ref} from "vue";
import {useCountStore} from "@/stores/count";
import {storeToRefs} from "pinia";
//数据
let n = ref(1)
//拿到数据并将其存入countStore
const countStore = useCountStore()
//解构
const {sum,school1,school2,bigSum} = storeToRefs(countStore)
//函数
function add() {
countStore.increment(n.value)
}
</script>
<template>
<div class="person">
<h2>当前求和为: {{ sum }} 放大十倍后 {{bigSum}}</h2>
<h2>{{school1}}</h2>
<h2>{{school2}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">加</button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
7` $subscribe
通过store的 $subcribe() 方法进行侦听 state 及其变化
<script setup lang="ts" name="count">
import {ref} from "vue";
import {useCountStore} from "@/stores/count";
import {storeToRefs} from "pinia";
//数据
let n = ref(1)
//拿到数据并将其存入countStore
const countStore = useCountStore()
//侦听
countStore.$subscribe((mutation, state)=>{
console.log('数据发生变化'+'本次修改信息为:'+mutation+'侦听的数据'+state)
})
//解构
const {sum} = storeToRefs(countStore)
//函数
function add() {
countStore.increment(n.value)
}
</script>
<template>
<div class="person">
<h2>当前求和为: {{ sum }}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
</select>
<button @click="add">加</button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
8` store组合式写法
// 引入仓库
import {defineStore} from "pinia";
import {reactive} from "vue";
import axios from "axios";
// 使用仓库 官方命名规则: use+文件名+Store
// defineStore参数1: id 推荐与文件名一致
// defineStore参数2: options 配置对象
export const useCountStore = defineStore('count', () => {
let countList = reactive(
JSON.parse(localStorage.getItem('countList') as string) || []
)
//相当于getCount函数,相当于action
async function getCount(value: any) {
// 发送请求,下面这行的写法是: 连续解构赋值+重命名
let {data: {content: title}} = await axios.get('https://api.uomg.com/api/...........')
//把请求回来的字符串,包装成一个对象
let obj = {id:nanoid(),title}
//放到数组中
countList.unshift(obj)
}
return {countList,getCount}
})
四` 通讯组件
1` props:
父传子 直接传递非函数 ;子传父 传递一个函数给子子调用父给的函数
2` 自定义事件
传参数的同时保留传递事件对象
@click=“text(6,7,$event)”
自定义事件常用于子给父传值
子组件
<script setup lang="ts" name="Person">
// 声明事件
import {onMounted} from "vue";
const emit = defineEmits(['haha'])
onMounted(() => {
setTimeout(() => {
//触发haha
emit('haha')
}, 3000)
})
</script>
<template>
<div class="person">
<button @click="emit('haha')"></button>
</div>
</template>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
</style>
父组件
<script setup lang="ts">
import router from "@/router";
import Person from "@/components/Person.vue";
function qwe() {
console.log('qwe')
}
</script>
<template>
<h1 ref="title2">主页</h1>
<!-- 给子组件Person绑定事件-->
<person @haha="qwe"/>
</template>
<style scoped>
</style>
3` mitt
安装:npm i mitt
mitt属于工具 存放于文件夹 utils/tools 中
于文件夹内新建文件emitter.ts
//引入mitt
import mitt from "mitt";
### ajax
1)ajax请求的原理/ 手写一个ajax请求?
2)readyState?
3)ajax异步与同步的区别?
4)ajax传递中文用什么方法?
![ajax.PNG](https://img-blog.csdnimg.cn/img_convert/5cabae7aa4de4ebf798029e548cf840a.webp?x-oss-process=image/format,png)
![前12.PNG](https://img-blog.csdnimg.cn/img_convert/ea139871b582836b40c4d47e5bb579af.webp?x-oss-process=image/format,png)
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
1` props:
父传子 直接传递非函数 ;子传父 传递一个函数给子子调用父给的函数
### 2` 自定义事件
传参数的同时保留传递事件对象
>
> @click="text(6,7,$event)"
>
>
>
自定义事件常用于子给父传值
子组件
父组件
主页
<person @haha=“qwe”/>
### 3` mitt
>
> 安装:npm i mitt
>
>
>
mitt属于工具 存放于文件夹 utils/tools 中
于文件夹内新建文件emitter.ts
//引入mitt
import mitt from “mitt”;
ajax
1)ajax请求的原理/ 手写一个ajax请求?
2)readyState?
3)ajax异步与同步的区别?
4)ajax传递中文用什么方法?
[外链图片转存中…(img-KddTSHYg-1715708675518)]
[外链图片转存中…(img-NzJIx2fP-1715708675519)]