一.了解工作原理:
一般面试官都会问,vue的数据驱动MVVM模式,M指数据部分,主要负责业务逻辑,V指视图部分,VM就是指数据与视图连接的数据模型,vm是像中转站,负责监听数据M的变化以及视图V的修改。要知道vue是单项数据流动,为什么这么说?有人会说v-model不是双向数据绑定吗,但是父子组件仍然遵循单项数据流,通过props传递值,子组件不可以直接修改props传递过来的值,我这里指的是简单数据类型,大家都知道引用数据类型指向内存的地址是唯一的,所以我们可以修改数组或对象里面的某个属性。当然不建议这么改,不然会可能会发生一些不可追踪的以及数据混乱的问题
二.创建vue项目方式:
确保安装了vue环境,
1.通过命令行
vue create project
2.从别人开源储存库拉取简单模板。
3.使用流行开源框架,例如若依框架,JEECG框架,JEECG集成的功能比较复杂,算平台级别的了,不过都需要先运行后端文件才能跑起前端项目哟!适合中小型企业级开发使用,代码生成器比较香。
三.开发用到的常用属性及方法:
1.监听watch:
简单数据监听:
data:{
meter:1000,
kilameter:1
},
watch:{
meter:function(val){
this.kilameter = val * 0.1;
},
kilameter:function(val){
this.meter = val *1000;
}
}
数据数据监听:
data:{
arr:[1,2,3]
},
watch:{
arr:function(newV,oldV){
console.log(newV);
console.log(oldV);
}
}
对象数据监听,注意深监听与执行效率:
data:{
obj : {
a:111,
b:222
}
},
watch:{
obj:{
handler:function(newV,oldV){
console.log(oldV);
},
immediate: true,//第一次绑定监听不会执行,加上此属性可立即执行
deep: true//监听对象需要深监听,不然多层嵌套的属性值被改变无法触发
}
}
值得注意的是对象监听还可以单独监听某个属性,一定要加引号:
watch: {
// 对象的监听写法
'form.price': function (val) {
}
},
2.计算属性computed,常用在订单金额计算,场景入购物车,特性是,当计算属性的依赖未发生改变时,再多处使用此属性都不会重新编译,有缓存机制,对视图有良好性能,写法如下
data(){
return {
b:10
}
}
computed:{
a(){
return this.b
}
}
3.全局状态管理store:
就是我们说的vuex,不过我现在比较喜欢使用vuex的进阶版pinia。pinia是轻量级的,速度比vuex快,但是不是用于开发大型应用哟,对付中小型项目,pinia戳戳有余。主要是比较喜欢pinia的写法简便,最大区别就是action了,我还是列举一下吧:
区别:
3-1.更改state数据,vuex是通过mutation默认传输state进行改变state的属性的值,如
state:{
a:1
},
mutation:{
put(state){
state.a=10
}
}
而pinia是这样,通过this改变,这可能看不出来多大变化,往下看,注意下面pinia是没有mutation的,只有action
state:{
a:1
},
action:{
put(){
this.a=10
}
}
3-2.pinia无mutation,我们知道vuex的mutation是写同步修改state操作,这就导致vuex再action里异步操作想要修改state的某个属性值要使用commit("mutation的方法名","要传递的值")提交给mutation,再mutation修改state的属性的值,这多麻烦啊,pinia的action可以写异步可以写同步,都是直接通过this修改state的。看这是不是少写了几行代码。pinia -》YYDS。
4.请求axios的二次封装,添加请求拦截器与响应拦截器,只是每个vue项目比做的,详细代码就不写了,网上百度一大把,毕竟每个人想做的需求有所不同,里面自由发挥,我就讲讲请求拦截器一般都是干嘛的吧,
请求拦截器:主要是拦截网络请求,验证权限,黑白名单,token这种,一般都是验证token是否携带及是否过期,如果不存在token就跳转登录,如果存在但是token又是过期的就重新调个刷新token的接口获取最新的token再去执行上次未完成的请求。
响应拦截器:主要是对后端返回的状态吗进行相应处理,像404,200,201,500啊这种,友好提示,及怎么处理。
5.路由守卫,分全局守卫与局部守卫:
全局守卫:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
独享守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
局部守卫实在组件内使用:
<template>
...
</template>
<script>
export default{
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
</script>
<style>
...
</style>
注意:
有的面试管会问守卫执行的先后顺序:
- 导航被触发(A–>B)
- 调用A组件内路由守卫beforeRouteLeave(to,from,next)
- 调用全局路由前置守卫router.beforeEach(to,from,next)
- 调用B路由独享守卫 beforeEnter(to,from.next)
- 解析异步路由组件B
- 调用B的组件内路由守卫beforeRouteEnter(to,from,next)
- 调用全局路由解析守卫 router.beforeResolve(to,from,next)
- 导航被确认
- 调用全局路由钩子router.afterEach(to,from)
- 渲染B组件DOM
6.熟练使用开源ui组件库,如ElementUI库·,Vant库,如果还会uniapp的话,就更好了。
7.自己封装一些工具,比如时间格式化,字符串序列化,这种
8.熟练使用promise分装异步操作,工作中常用哦。
9.vue项目完成的一些打包配置,看跟人需求,网上百度有许多基本配置,也够用了,高深的也不太懂,主要有webpack与vite,听说vite快一点。我个人觉得会用哪个就用哪个。
基本配置:
const path = require('path')
// 1. 导入 html-webpack-plugin 这个插件,得到插件的构造函数
const HtmlPlugin = require('html-webpack-plugin')
// 2. new 构造函数,创建插件的实例对象
const htmlPlugin = new HtmlPlugin({
// 指定要复制哪个页面
template: './src/index.html',
// 指定复制出来的文件名和存放路径
filename: './index.html'
})
// 注意:左侧的 { } 是解构赋值
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// 使用 Node.js 中的导出语法,向外导出一个 webpack 的配置对象
module.exports = {
// 在开发调试阶段,建议大家都把 devtool 的值设置为 eval-source-map
// devtool: 'eval-source-map',
// 在实际发布的时候,建议大家把 devtool 的值设置为 nosources-source-map 或直接关闭 SourceMap
devtool: 'nosources-source-map',
// mode 代表 webpack 运行的模式,可选值有两个 development 和 production
// 结论:开发时候一定要用 development,因为追求的是打包的速度,而不是体积;
// 反过来,发布上线的时候一定能要用 production,因为上线追求的是体积小,而不是打包速度快!
mode: 'development',
// entry: '指定要处理哪个文件'
entry: path.join(__dirname, './src/index1.js'),
// 指定生成的文件要存放到哪里
output: {
// 存放的目录
path: path.join(__dirname, 'dist'),
// 生成的文件名
filename: 'js/bundle.js'
},
// 3. 插件的数组,将来 webpack 在运行时,会加载并调用这些插件
plugins: [htmlPlugin, new CleanWebpackPlugin()],
devServer: {
// 首次打包成功后,自动打开浏览器
open: true,
// 在 http 协议中,如果端口号是 80,则可以被省略
port: 80,
// 指定运行的主机地址
host: '127.0.0.1'
},
module: {
rules: [
// 定义了不同模块对应的 loader
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
// 处理 .less 文件的 loader
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] },
// 处理图片文件的 loader
// 如果需要调用的 loader 只有一个,则只传递一个字符串也行,如果有多个loader,则必须指定数组
// 在配置 url-loader 的时候,多个参数之间,使用 & 符号进行分隔
{ test: /\.jpg|png|gif$/, use: 'url-loader?limit=470&outputPath=images' },
// 使用 babel-loader 处理高级的 JS 语法
// 在配置 babel-loader 的时候,程序员只需要把自己的代码进行转换即可;一定要排除 node_modules 目录中的 JS 文件
// 因为第三方包中的 JS 兼容性,不需要程序员关心
{ test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
]
},
resolve: {
alias: {
// 告诉 webpack,程序员写的代码中,@ 符号表示 src 这一层目录
'@': path.join(__dirname, './src/')
}
}
}
10.还要掌握echarts库的使用,大概了解图表的组成部分,及配置写法,会看文档。
总结:闭门造车,不如面试收集当下技术,再对应消化吸收备战大厂。脸皮要厚