概述
1. 路由懒加载
为什么需要懒加载?
像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,
时间过长,会出啊先长时间的白屏,即使做了loading也是不利于用户体验,
而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时
三种方式: vue异步组件; es提案的import(); webpack的require,ensure()
1). vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 . 但是,这种情况下一个组件生成一个js文件
实现原理:将路由相关的组件,不再直接导入了,而是改写成异步组件的写法,只有当函数被调用的时候,才去加载对应的组件内容
/* vue异步组件技术 */
2). 组件懒加载方案二 路由懒加载(使用es6提出的import)
const 组件名=() => import(‘组件路径’);
// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件
const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about')
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。
// 把组件按组分块
const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
3). 组件懒加载方案三: webpack提供的require.ensure()
项目中用的:
2. 动态绑定class 动态class对象:
<div :class="{ 'is-active': true, 'red': isRed }"></div>
动态class数组:
<div :class="['is-active', isRed ? 'red' : '' ]"></div>
动态style对象:
<div :style="{ color: textColor, fontSize: '18px' }"></div>
动态style数组:
<div
:style="[{ color: textColor, fontSize: '18px' }, { fontWeight: '300' }]"
></div>
项目: :class="{ light: ['05', '09', '10'].indexOf(item.status) > -1 }"
项目中会用到的:
<el-col v-for="(btn, index) in btnArr" :key="index" :style="{width: multiWidth}">...</el-col>
<script>
...
computed: {
multiWidth () {
switch (option.length) {
case 1:
return 100 + '%'
case 2:
return 50 + '%'
case 3:
return 33 + '%'
case 4:
return 25 + '%'
}
}
}
</script>
3. VUE跨域问题
项目中使用的: 解决跨域问题 配置代理 跨域问题,vue中使用代理的方式解决:
vue.config.js文件中:
module.exports = {
// baserUrl:'/',
//配置根目录
outputDir:'dist',
//构建输出
assetsDir:'assets',
//静态资源目录
lintOnSave:false,
//是否开启eslint保存检测
devServer:{
open:true,
//启动项目之后不会立即运行
host:'localhost',
//主机名称
// port:8080,
//端口号,默认就是8080
https:false,
hotOnly:false,
//热更新
proxy:{
'/api':{
// 引号中代表监测的是以 /api 开头的接口
target:'http://10.130.64.139:30700/xlink-admin-dev',
ws:true,
changeOrigin:true,
// 是否跨域
pathRewrite:{
'^/api':''
}
}
}
}
}
target: // 代表监测到以 /api 开头的接口后,把axios请求中前面 的本地服务器地址改为后端接口地址,实际发送给后端的请求就是下方后一个请求;
http://localhost:8080 -->http://10.130.64.139:30700/xlink-admin-dev
pathRewrite :检查代理的请求中是否有 /api ,有的话把 /api 替换为冒号后面的内容,案例为替换成空字符串,也就是删去 /api 。(^是正则表达式的内容,意思是限定开头)
跨域的解决方案:
同源策略: 只有当协议,域名,端口一致,才是同源。
协议,域名,端口,任何一个不一致,都会产生跨域问题。
如何解决:
1)CORS
2)JSONP: 主要是利用script标签没有跨域限制的特性来完成的。
3)vue代理服务器proxy跨域:通过请求本地的服务器,然后本地的服务器再去请求远程的服务器(后端部署的接口服务器),
最后本地服务器再将请求回来的数据返回给浏览器(本地服务器和浏览器之间不存在跨域)
两个关键点:
本地服务器(利用node.js创建的本地服务器进行代理,也叫代理服务器)和浏览器之间不存在跨域
服务器和服务器之间不存在跨域
补充跨域基础指示:
1)什么是跨域?
简单来讲,跨域是指从一个域名的网页去请求另一个域名的资源。比如从百度(baidu.com)页面去请求我的博客(blog.pangao.vip)的资源。但由于有同源策略的关系,一般是不允许这么直接访问的。
2) 什么是同源策略?
一言蔽之,同源就是协议、域名和端口都相同。
3)为什么要有同源策略?
试想,如果你刚刚在网银输入账号密码,查看了自己还有1万块钱,紧接着访问一些不规矩的网站,这个网站可以访问刚刚的网银站点,并且获取账号密码,那后果可想而知。所以,从安全的角度来讲,同源策略是有利于保护网站信息的。
4)为什么要跨域
然而,有一些情况下,我们是需要跨域访问的。比如,程序员开发网站,就有可能需要在本地访问服务器的数据。再比如某公司的A页面(a.pangao.vip)有可能需要获取B页面(b.pangao.vip)。
配置@src路径:
在jsconfig.json文件中,配置src @属性
{ “compilerOptions”:
{ “baseUrl”: “./”,
“paths”: { “@/": ["src/”] }, “experimentalDecorators”: true } }加粗样式
4. VUE脚手架
node_modules: 项目依赖文件 Public:
一般存放静态资源,放在这里的静态资源,webpack打包的时候,回原封不动的打包到dist文件件。
Src: 程序员源代码文件夹;
assets: 静态资源,
在webpack打包的时候会把静态资源当做一个模块,打包到js文件中。
Components: 非路由组件+全局组件
App.vue: 唯一的根组件
Main.js:程序入口文件,整个程序中最先执行的文件;
bebel.config.js: 配置文件(babel相关)
package.json:项目的身份证;
5. Promise- Axios,ajax,fetch Ajax,jQuery
1)Promise
Promise主要用于解决异步回调嵌套的问题。
当多个ajax请求之间存在依赖关系,也就是说一个请求必须使用另一个请求返回的结果时,
需要将这个请求嵌套在另一个请求的回调函数上,才能使用另一个请求的结果来发送这个请求。
Promise的思路是将异步请求作为一个对象,将执行成功和失败作为这个对象的方法,
执行成功的时候将结果放到这个对象的then方法中处理后续的逻辑,失败调用catch方法。这样调用它就避免了回调函数的嵌套。
使用场景: 主要用于保证多个异步请求都完成以后,再进行后续的业务。
resolve成功状态
reject拒绝状态
then是前面返回promise的处理
Promise的相关概念
(ES6新语法 用来处理异步编程
promise是一个对象 可以获取异步操作的消息
可以避免多层异步调用嵌套的问题(回调地狱)
提供了简洁的API 使得控制异步操作更加容易
基于promise发送ajax请求)
Promise常用的API
1.实例方法
.then() 得到异步任务的正确结果
.catch() 得到异常信息
.finally() 成功与否都会执行
2.对象方法
Promise.all() 并发处理多个异步任务 所有任务都执行完成才能得到结果
-
什么是async/await?
对于async/await,我总结为一句话async/await是generator + Promise的语法糖,它用同步方式执行异步代码 -
ajax,axios和fetch的区别 Ajax:
—ajax自然不必说,最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,
多个请求之间如果有先后关系的话,就会出现回调地狱。
Jquery Ajax:
是jQuery框架中的发送后端请求技术,由于jQuery是基于原始的基础上做的封装,所以,jquery
Ajax自然也是原始ajax的封装
—Fetch:
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。
Fetch的代码结构比起ajax简单多了,参数有点像jQuery
ajax。但是,一定记住fetch不是ajax的进一步封装,
而是原生js。Fetch函数就是原生js,没有使用XMLHttpRequest对象。
1)fetchtch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理。
2)fetch默认不会带cookie,需要添加配置项。
3)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费。
4)fetch没有办法原生监测请求的进度,而XHR可以
<script>
// 原生XHR
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText) // 从服务器获取数据
}
}
xhr.send();
</script>
<script>
// fetch
fetch(url).then(response => {
if (response.ok) {
response.json()
}
}).then(data => console.log(data)).
catch (err => console.log(err))
</script>
—axios:
axios不是原生JS的,需要进行安装,它不但可以在客户端使用,也可以在nodejs端使用。
Axios也可以在请求和响应阶段进行拦截。同样也是基于promise对象的。
axios优缺点
- 从浏览器中创建XMLHttpRequests
- 从node.js创建http请求
- 支持promise API
- 拦截请求与响应
- 转换请求数据与响应数据
- 取消请求
- 自动转换JSON数据
- 提供了一些并发请求的接口
封装axios步骤:
<script>
import axios from "axios";
//1、对axios二次封装
const requests = axios.create({
//基础路径,requests发出的请求在端口号后面会跟改baseURl
baseURL: "/api",
timeout: 5000,
});
//2、配置请求拦截器
requests.interceptors.request.use(config => {
//config内主要是对请求头Header配置
//比如添加token
return config;
});
//3、配置响应拦截器
requests.interceptors.response.use(
res => {
//成功的回调函数
return res.data;
},
error => {
//失败的回调函数
console.log("响应失败" + error);
return Promise.reject(new Error("fail"));
}
);
//4、对外暴露
export default requests;
</script>
请求接口封装:
<script>
//当前模块,API进行统一管理,即对请求接口统一管理
import requests from "@/api/request";
//首页三级分类接口
export const reqCateGoryList = () => {
return requests({
url: "/product/getBaseCategoryList",
method: "GET",
});
};
</script>
使用的时候直接导入到页面
<script>
import {reqCateGoryList} from './api'
//发起请求
reqCateGoryList();
</script>
面试总结:
ajax: 指的是 XMLHttpRequest(XHR),最早出现的向后端发送请求的技术,隶属于原始 js 中, 核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现 回调地狱。
axios: 是一个基于 Promise 的 http请求库,本质上也是对原生XHR的封装,只不过它是Promise 的实现版本,符合最新的ES规则。
axios 的特征:
1、从浏览器中创建XMLHttpRequest
2、支持 Promise API
3、客户端支持防止 CSRF
4、提供了一些并发请求的接口(重要,方便了很多的操作)
5、从 node.js 创建 http 请求
6、拦截请求和响应
7、转换请求和响应数据
8、取消请求
9、自动转换JSON数据
fetch 号称是 AJAX 的替代品,是在 ES6 出现的,使用了ES6 中的 promise 对象。Fetch 是基于 promise 设计的。
Fetch 的代码结构比起 ajax 简单多了, 参数有点像 JQuery ajax。 但是,
一定要记住: fetch 不是 ajax的进一步封装,而是原生 JS , 没有使用 XMLHttpRequest 对象。
fetch使用的时候,一般需要封装
Promise主要用于解决异步回调嵌套的问题。
6. HTTP状态码详解200,404,500
1开头的: 表示目前是协议处理的中间状态,还需要后续操作;
2开头的: 代表请求已成功被服务器接收、理解、并接受。这系列中最常见的有200、201状态码。
3开头的:代表需要客户端采取进一步的操作才能完成请求,这些状态码用来重定向,
后续的请求地址(重定向目标)在本次响应的 Location 域中指明。
补充: 重定向状态码用来告诉浏览器客户端,它们访问的资源已被移动, Web服务器发送一个重定向状态码和一个可选的Location Header, 告诉客户端新的资源地址在哪。
4开头的:表示请求错误。代表了客户端看起来可能发生了错误,妨碍了服务器的处理。常见有:401、404状态码。
400 服务器不理解请求的语法。
401 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 服务器拒绝请求。
404 服务器找不到请求的网页。
405 禁用请求中指定的方法。
5开头的,不常见:
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应
7. 防抖与节流
防抖: 频繁去触发一个事件,但是只触发最后一次。以最后一次为准;
1、input框变化频繁触发事件可加防抖
2、频繁点击按钮提交表单可加防抖
节流: 频繁去触发一个事件,但是只能每隔一段时间触发一次;
1、滚动频繁请求列表可加节流
2、游戏里长按鼠标,但是动作都是每隔一段时间做一次
8. vue中的ref
ref 被用来给DOM元素或子组件注册引用信息。引用信息会根据父组件的 $refs 对象进行注册。
如果在普通的DOM元素上使用,引用信息就是元素; 如果用在子组件上,引用信息就是组件实例
注意:只要想要在Vue中直接操作DOM元素,就必须用ref属性进行注册
- vue中的$nextTick()
nextTick在下一次DOM更新结束后,执行其指定的回调。
“嘿,如果你想在DOM更新后执行一个函数(这种情况很少发生),我希望你使用nextTick而不是setTimeout”。
9.路由守卫
- 定义:
导航守卫就是路由跳转前、中、后过程中的一些钩子函数,这个函数能让你操作一些其他的事儿,这就是导航守卫。 - 路由守卫分类
导航守卫分为:全局的、组件内的、单个路由独享三种
1)全局路由守卫(钩子函数)
定义: 路由实例上直接操作的钩子函数,他的特点是所有配置路由的组件都会触发。
它的钩子函数有: beforeEach, beforeResolve, afterEach
//* 前置路由首位 每次路由切换之前被调用,初始化之前被调用
// 切换前调用
router.beforeEach((to, from, next) => {
// 根据条件判断是否放行,一般用于登录验证
})
// 后置路由守卫:路由跳转完成后触发,参数包括to,from,发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫)之前。
// 切换后调用
router.afterEach((to, from) => {
// 后置路由守卫
})
2)单个路由独享
指在单个路由配置的时候也可以设置的钩子函数
beforeEnter:与全局的beforeEach完全相同,如果都设置则在beforeEach之后紧随执行,参数to、from、next
只有前置路由守卫,没有后置守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
3)组件内的
指在组件内执行的钩子函数,类似于组件内的生命周期
<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>
10. 单页面SPA(singal page application)
单页面Spa
概念: 只有一个html页面,所以跳转的方式是组件之间的切换;
优点: 跳转流畅,组件化开发,组件可复用, 开发便捷
缺点: 首屏加载过慢,seo优化不好
多页面开发Mpa
概念: 有多个页面,跳转方式是页面之间的跳转;
优点: 首屏加载速度快,seo友好;
缺点: 跳转流畅的问题
11.MVVM是什么?和MVC有何区别呢?
MVC:
Model(模型):负责从数据库中取数据
View(视图):负责展示数据的地方
Controller(控制器):用户交互的地方,例如点击事件等等
思想:Controller将Model的数据展示在View上
MVVM:
VM:也就是View-Model,做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,
即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,
即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。
思想:实现了 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素,
来改变 View 的显示,而是改变属性后该属性对应 View 层显示会自动改变(对应Vue数据驱动的思想)
区别
整体看来,MVVM 比 MVC 精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,
不用再用选择器操作 DOM 元素。因为在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也观察不到 View,
这种低耦合模式提高代码的可重用性。
Vue是不是MVVM框架?
Vue是MVVM框架,但是不是严格符合MVVM,因为MVVM规定Model和View不能直接通信,而Vue的ref可以做到这点
12. 生命周期
beforeCreate(初始化界面,创建vue实例之前)
created(初始化界面后,实例创建成功,一般在这里实现数据的异步操作)
beforeMount(渲染dom前,虚拟dom)
mounted(真实dom渲染完毕,可以获取真实的DOM)
beforeUpdate(更新数据前)
updated(更新数据后)
beforeDestroy(销毁组件)
destroyed(销毁组件后)
声明周期的其他三个钩子函数: component, keep-alive,
component 和keep-alive 都是内置组件,在VUE代码已经内置好的组件;
闭合标签使用组件
component : 内置组件,根据is属性来显示对应的组件;is属性的属性值保持和组件名字一致;然后可以显示对应的组件
component: 每次能动态显示一个组件,当切换下一个组件时,当前组件要销毁
13 keep alive
定义: 在开发Vue项目的时候,大部分组件是没必要多次渲染的,所以Vue提供了一个内置组件keep-alive来缓存组件
内部状态,避免重新渲染,提高性能,缓存的组件不需要销毁,也不需要再创建
使用场景:
缓存路由组件:可以将所有路径匹配到的路由组件都缓存起来,包括路由组件里面的组件,keep-alive大多数使用场景就是这种。
声明周期钩子函数:
在被keep-alive包含的组件/路由中,会多出两个生命周期的钩子:activated 与 deactivated
进入keep-alive包裹的组件,调取activated钩子,离开,调取deactivated钩子
钩子函数的属性:
include:匹配的 路由/组件 会被缓存
exclude:匹配的 路由/组件 不会被缓存
14. 父子生命周期顺序
父beforeCreate => 父created => 父beforeMount =>
子beforeCreate => 子created =>子beforeMount => 子Mounted=>父Mounted
子组件先挂载 然后到父组件,更新也类似
父beforeUpdate =>子beforeUpdate => 子updated => 父updated
15. vue中的data 为什么是函数返回 而不是直接一个对象呢?
data之所以只一个函数,是因为一个组件可能会多处调用,而每一次调用就会执行data函数并返回新的数据对象,
这样,可以避免多处调用之间的数据污染。
16. 项目优化
代码层面: 1, v-if w-show; 2. computed methods 3, v-for 添加key,4 图片资源懒加载,
5. 路由懒加载 6. 第三方组件,按需导入, 7. 不需要双向响应的数据放在data外;
17.get与post区别
get:
- get: https://api.github.com/search/users?q=JakeWharton 就是一个非常典型的 GET 请求的表现形式,
即请求的数据会附在 URL 之后(放在请求行中),以 ? 分割 URL 和传输数据,多个参数用 & 连接。 - GET 是会被浏览器主动缓存的,如果下一次传输的数据相同,那么就会返回缓存中的内容,以求更快地展示数据。
- GET 方法的 URL 一般都具有长度限制,但是需要注意的是 HTTP 协议中并未规定 GET 请求的长度。
这个长度限制主要是由浏览器和 Web 服务器所决定的,并且各个浏览器对长度的限制也各不相同。 - GET 方法只产生一个 TCP 数据包,浏览器会把请求头和请求数据一并发送出去,服务器响应 200 ok(返回数据)
post: - POST 是将请求信息放置在请求数据中的,这也是 POST 和 GET 的一点不那么重要的区别。POST相对来说更安全一些。
- 因为 POST 方法的请求信息是放置在请求数据中的,所以它的请求信息是没有长度限制的。
- 根据 HTTP 规范,POST 表示可能修改变服务器上的资源的请求。例如我们在刷知乎的时候对某篇文章进行点赞,
就是提交的 POST 请求,因为它改变了服务器中的数据(该篇文章的点赞数)
18. 用过哪些vue的修饰符?
.trim(): v-model绑定的值得收尾空格过滤掉;
.once() 事件只执行一次;
.native() 加在自定义组件的事件上,保证事件能执行;
,sync 父子组件传值,子组件想要更新这个值,使用此修饰符可简写;
.prevent修饰符: 阻止事件的默认行为,如下案例中,链接地址“去百度页”不会跳转到百度页面中;
<div class="prevent">
<!-- 使用 .prevent 阻止默认行为 -->
<p>
<a href="http://www.baidu.com" @click.prevent="linkClick">去百度页</a>
</p>
<a href="http://www.baidu.com" @click.prevent="linkClick">去百度页</a>
</div>
.stop() 阻止事件的冒泡行为;
<template>
<!-- @click.stop="btnClick"中的stop用于阻止事件的冒泡,不然点击button,回打印出:按钮点击了----div点击了 -->
<div id="app">
<div @click="divClick">
div内容<input type="button" value="按钮" @click.stop="btnClick">
</div>
</div>
</template>
<script>
export default {
data(){
return{
}
},
methods:{
btnClick(){
console.log('按钮点击了!')
},
divClick(){
console.log('div点击了!')
}
},
}
</script
.self 只会阻止自己身上冒泡行为的触发,并不会真正阻止 冒泡的行为
<template>
<!-- .self 只会阻止自己身上冒泡行为的触发,并不会真正阻止里层元素的冒泡的行为
点击普通按钮,会继续向上冒泡,只是第二层div2不会被打印,因为设置了self
-->
<div class="outer" @click="divHandler1">最外层的div1
<div class="inner" @click.self="divHandler2">第二层div2
<input
type="button"
value="普通按钮"
@click="btnHandler"
style="margin-top: 100px"
/>
</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods: {
divHandler1() {
console.log("这是触发了
div1 的点击事件");
},
divHandler2() {
console.log("这是触发了 div2 的点击事件");
},
btnHandler() {
console.log("这是触发了 btn 按钮 的点击事件");
},
},
};
</script>
stop与self的区别:
stop就是阻止冒泡行为,.self 只会阻止自己身上冒泡行为的触发,并不会真正阻止里层元素的冒泡的行。
19. vue的指令
v-text v-html v-show v-if v-else v-else-if
v-for v-on v-bind(动态绑定各种变量) v-model v-slot(插槽名), v-once(元素与组件只渲染一次)
20. 组件之间的传值方式/
父给子组件传值,子组件使用props进行接收;
子组件给父组件传值,子组件使用$emit+事件 进行传值;
$refs获取组件实例,进而获取数据
使用vuex进行状态管理
21. 路由有哪些模式?区别
hash模式: 通过#号后面内容的更改,触发事件,实现路由切换;
是什么?
在浏览器链接中符号“#”后面的字符称之为hash,用window.location.hash读取;
特点
hash虽然在URL中,但不被包括在HTTP请求中;
仅用来指导浏览器动作,对服务端安全无害,
hash不会重新加载页面。
history模式: 通过pushState和replaceState切换url,触发popstate事件,实现路由切换,需要后端配合
是什么
history模式是采用HTML5的新特性;且提供了两个新方法:pushState()、replaceState()
可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
特点
history 模式下,前端的 URL 被包括在HTTP请求中,如 http://www.xxx.com/items/id。
如果后端有对请求接口的地址进行管理,同时缺少对其相应路由的处理的话,那就将返回 404 错误。
(也就是说,后台处理某个接口只能针对某个页面链接请求,其它页面请求该接口将无法请求通)
22. computed 与watch
computed有缓存机制,依赖不变的话,会直接读取缓存进行复用,不能进行异步;
watch,监听某一个变量的变化,可以进行异步;
另外补充:watch的相关知识
<script>
// 监听基本数据类型
watch: {
value () {
// do something
}
// 监听引用数据类型
watch: {
obj: {
handler () { // 执行回调
// do something
},
deep: true, // 是否进行深度监听
immediate: true // 是否初始执行handler函数
}
}
}
23. vuex
定义:状态管理工具;
五个属性:
state : 定义了应用状态的数据结构,可以在这里设置默认的初始状态;
mutations: 唯一改变store中状态的方法,必须是同步函数
actions : 用于提交mutations, 可以进行异步操作
getter: 允许组件从store中获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。
modules : 允许将单一的store拆分为多个store,且同时保存在单一的状态数中。
mapState,
<!-- 页面中使用 -->
import { mapState, mapMutations } from 'vuex';
computed: {
...mapState('giftInsuranceBcf', ['productInfo', 'insurantList', 'insureList']),
}
methods: {
...mapMutations('giftInsuranceBcf', ['setProductInfo', 'setInsurantList', 'setInsureList']),
}
<!-- vuex -->
const state = {
basicInfo: {} //投保确认基础信息
};
const mutations = {
setBasicInfo(state, model) {
state.basicInfo = model;
}
};
export default {
namespaced: true,
state,
mutations
};
// vuex
const state = {
productInfo: {}, //产品信息
insurantList: [
], //投保人信息
insureList: [] //被保人信息
};
const mutations = {
setProductInfo(state, model) {
state.productInfo = model;
},
setInsurantList(state, model) {
if (!Array.isArray(model)) {
for (let i in model) {
state.insurantList[0][i] = model[i];
}
} else {
state.insurantList = model;
}
},
};
export default {
namespaced: true,
state,
mutations
};
24. 不需要的响应式的数据,怎么处理?
需要响应式的数据放在data中,
不需要响应的数据,则需要做下处理,以免进行过多内存消耗;
<script>
// 方法一:将数据定义在data之外
data(){
this.list1 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
return {}
};
// 方法二:Object.freeze()
data () {
return {
list1: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
}
}
</script>
25. vue.nextTick()的用处
nextTick(),是将回调函数延迟在下一次dom更新数据后调用,
简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,
24 插槽
插槽就是子组件中的提供给父组件使用的一个占位符,使用表示, 父组件可以在这个占位符填充内容,
填充的内容会替换子组件的标签;
1)单个插槽/匿名插槽/插槽的基本使用
<html>
<!-- 子组件child -->
<template>
<div>
<h1>今天天气状况:</h1>
<slot></slot>
// 占位置
</div>
</template>
<script>
export default {
name: 'child'
}
</script>
<!-- 父组件 -->
<div>
<child>
<!-- 父组件给这个占位符填充内容 -->
<div style="margin-top: 30px">多云,最高气温34度,最低气温28度,微风</div>
</child>
</html>
2)具名插槽
给插槽取个名字,可以放多个插槽,父组件根据名字把内容填充到对应的插槽中
<html>
<!-- 子组件 -->
<div class="header">
<h1>我是页头标题</h1>
<slot name="header"></slot>
</div>
<div class="footer">
<h1>我是页尾标题</h1>
<slot name="footer"></slot>
</div>
<!-- 父组件 -->
<child1>
<template slot="header">
<p>我是页头的具体内容</p>
</template>
<template slot="footer">
<p>我是页尾的具体内容</p>
</template>
</child1>
</html>
编译作用域: slot 其实就是能够让我们在父组件中添加内容到子组件的‘空间’。
我们可以添加父组件内任意的data值,但是不可以使用子组件内的数据;
因为:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
父组件想使用子组件的数据: 使用slot-scope的方式
<html>
<!-- 父组件 -->
<child>
<!-- 父组件使用子组件data中的数据slotone -->
<template v-slot:one='slotone'>
{{ slotone.value1 }}
// 通过v-slot的语法 将子组件的value1值赋值给slotone
</template>
<template v-slot:default='slotde'>
{{ slotde.value2 }}
// 同上,由于子组件没有给slot命名,默认值就为default
</template>
</child>
</html>
26. Vue的SSR是什么? 有什么好处?
SSR就是服务端渲染。
基于nodejs server服务端开发,所有的html代码在服务端渲染;
数据返回给前端,然后前端进行激活,即可成为浏览器标识的html代码
SSR首次加载更快,有更好的用户体验,有更好的seo优化。
27. mixins混入
几个组件,共享同一个配置。
定义一个混入对象,把混入对象混入到当前的组件中
vuex:用来做状态管理的,里面定义的变量在每个组件中均可以使用和修改,在任一组件中修改此变量的值之后,
其他组件中此变量的值也会随之修改。
Mixins:可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,值的修改在组件中不会相互影响。
mixins详细使用介绍
28. 路由的跳转方式:
总结:
1)直接修改地址栏中的路由地址。
通过router-link实现页面按钮式路由跳转
<router-link to="/myRegister">注册</router-link></router-link>
2)this.$router.push进行编程式路由跳转
this.$router.push('/myLogin');
this.
r
o
u
t
e
.
p
a
r
a
m
s
、
t
h
i
s
.
route.params、this.
route.params、this.route.query获取路由传递参数;
params 和 query 都是传递参数的,params不会在url上面出现,并且params参数是路由的一部分,是一定要存在的。 query则是我们通常看到的url后面的跟在?后面的显示参数
1)使用router-link进行路由导航,传递参数;
=>父组件中: 使用标签进行导航
<el-col>
<router-link to = "/child/123"><el-button>click</el-button>
</el-col>
注意:child是子页面路由路径,123是需要传递的参数
=>子组件中:使用this.$route.params.num来接收路由参数
<template>
<div class="child"> {{num}}</div>
</tempalte>
<script>
export default{
name:"child",
data(){
return{
num:0
}
},
mounted(){
this.num = this.$route.params.num
// 123
}
}
</script>
此时,页面上渲染出路由传递过来的参数num,呈现123
=>路由配置文件中:
{
path:"/child/:num",
name:"child",
component:Child,
}
num用来为参数占位
=>地址栏中:localhost:8080/#/child/123
在地址栏中显示传递的参数num,即123, ,刷新页面,参数不丢失
2)直接调用$router.push 实现携带参数的跳转
=> 父组件中:
<template>
<ul>
<li v-for="itemId in 3" :key="itemId" @click="toChild(itemId)">{{itemId}}</li>
</ul>
</template>
<script>
export default{
name:"home",
data(){
tableData:[]
},
methods:{
toChild(id){
this.#router.push({
paht:`/child/${id}`
})
}
}
}
</script>
模板渲染中调用函数,传递参数
=> 子组件中:
<template>
<div class="child">
{{this.$route.params.id}}
</div>
</template>
仍然使用 this.$route.params.id 获取参数
=> 路由配置文件中:
{
path:"/child/:id",
name:"child",
component:Child,
}
id用来为参数占位
=> 地址栏中:locahost:8080/#/child/1
在地址栏中显示传递的参数id, ,刷新页面,参数不丢失.
3)通过路由属性中的name来确定匹配的路由,通过params来传递参数
<template>
<el-button @click="toChild">click</el-button>
</template>
<script>
export default{
name:"home",
data(){
tableData:[]
},
methods:{
toChild(id){
this.#router.push({
name:"childView"
params:{
id:1
}
})
}
}
}
</script>
使用name来匹配路由
=> 子组件中:
<template>
<div class="child">
{{this.$route.params.id}}
</div>
</template>
依然使用 this.$route.params.id 接收参数
=> 路由配置问件中:
{
path:"/child",
name:"childView",
component:Child,
}
使用name匹配
=> 地址栏中:localhost:8080/#/child
地址栏中不显示参数,刷新页面,参数丢失
4)使用path来匹配路由,然后通过query来传递参数,这种情况下 query传递的参数会显示在url后面?id=?
=> 父组件中:
<template>
<el-button @click="toChild">click</el-button>
</template>
<script>
export default{
name:"home",
data(){
tableData:[]
},
methods:{
toChild(){
this.#router.push({
path:"/child"
query:{
id:1
}
})
}
}
}
</script>
使用query来传递参数
=> 子组件中:
template>
<div class="child">
{{this.$route.query.id}}
</div>
</template>
使用 this.$route.query.id来接收参数
=> 路由配置文件中:
{
path:"/child",
name:"child",
component:Child,
}
=> 地址栏中:localhost:8080/#/child?id=1
总结:
- query相当于是get, 页面跳转时,url中有请求的参数。 params相当于post请求,参数不会先url中显示;
- 值得注意的是: params 传参时, F5刷新是参数会丢失, query传参则不会
29. r o u t e 与 route与 route与router的区别
1)$route:是指当前正在跳转的路由对象,每一个路由都会有一个route对象,包含path,params,hash,query,fullPath,matched,name等路由信息属性。,
即路由实例$router跳转到的当前的路由对象$route;
路由实例 可以包含多个 路由对象,它们是父子包含关系,用法如下:
this.$route.params // 获取当前路由对象传递过来的参数
this.$route.query // 获取当前路由对象传递过来的参数
2)$router:是指VueRouter的实例,包含了路由跳转的方法、钩子函数等
$router操控整个路由,用法如下:
this.$router.go(-1) // 向前或者向后跳转n个页面,n可为正整数或负整数
this.$router.push('/') // 跳转到指定url路径,history栈中会有记录,点击返回会跳转到上个页面
this.$router.replace('/') // 跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面
30. VUE页面跳转刷新参数丢失问题解决
1. vue 中的路由跳转可以通过路径跳转, 页可用通过 路由的 name 属性进行跳转
2. 路由跳转是携带参数有两种方式
<script>
this.$router.push({
name: 'xxxx',
params: {}
})
this.$router.push({
name: 'xxxx',
query: {}
})
// 值得注意的是: params 传参时, F5刷新是参数会丢失, query传参则不会
另外, 如果不想使用路由传参, 可以考虑使用 sessionStrong 或者 localStorage,
首先sessionStoreage是将数据放到session中(临时),直到浏览器关闭为止,
localStoreage是放在本地存储中(持久),
想了想还是sessionStoreage好一点,毕竟程序员都很懒,其实是我不想再去往代码中添加一个清除的代码很累。
sessionStorage并不支持存储对象,需要将对象转为json串,再存入sessionStorage,取出时再转为js对象
存储进去:
JSON.stringify(value),先转为json字符串;
JSON.parse(value);//json串转为js对象;
31. session, cookie, token的区别
1)http是无状态协议,当浏览器给服务器发送请求,服务器响应客户请求。但是同一个浏览器再次发送请求,服务器
并不知道它是刚才的那个服务器。简单来说,服务器不会记得你,这就是http无状态协议。
2)保存用户状态的两大机制: session会话, cookie
3)session简介: 最早保存记录的方式在session中,保存在服务端,服务器压力太大;
服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。相对cookie更安全。
于是就有人思考,可以把数据保存在客户端,cookie,与token
cookie简介: 是web服务器保存在客户端上的一系列文本信息;
典型应用: 判断该用户是否登录过网站; 购物车处理;
cookie的作用: 对特定对象的追踪; 保存用户网页浏览的记录与习惯, 简化登录‘
有安全风险: 容易泄露用户信息;
session: 在服务端保存信息; 保存的信息是object类型,关闭窗口就消失,保存重要信息;
cookie: 在客户端保存信息; 保存的信息字符串类型; 信息可以长期保存到客户端; 保存不重要的信息;
token简介: token是多用户下处理认证的最佳方式;
特点:无状态,可拓展;
支持移动设备; 跨程序调用; 安全;
token验证身份的过程:用户通过用户名密码发送请求----> 程序验证 --->程序返回一个签名的token给客户端
---> 客户端储存token, 并且每次用于发送请求 ---> 服务端验证token并返回数据
32 vue中事件修饰符详解(stop, prevent, self, once, capture, passive)
.stop 是阻止冒泡行为,不让当前元素的事件继续往外触发,如阻止点击div内部事件,触发div事件
.prevent 是阻止事件本身行为,如阻止超链接的点击跳转,form表单的点击提交
.self 是只有是自己触发的自己才会执行,如果接受到内部的冒泡事件传递信号触发,会忽略掉这个信号
.capture 是改变js默认的事件机制,默认是冒泡,capture功能是将冒泡改为倾听模式
.once 是将事件设置为只执行一次,如 .click.prevent.once 代表只阻止事件的默认行为一次,当第二次触发的时候事件本身的行为会执行
.passive 滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 onScroll 完成。这个 .passive 修饰符尤其能够提升移动端的性能。
补充:
1>事件冒泡:
IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点,看一下以下示例:
// 方法1, 使用.stop
<div @click="test1()">
<span @click.stop="test2()">按钮1</span>
<span>按钮2</span>
</div>
// 方法二:可以自己写个阻止冒泡事件 然后在发生冒泡的元素中调用这个事件:@click=“_stopPropagation($event)”
methods:{
_stopPropagation(ev){
var _this = this;
ev.stopPropagation();
},
}
这样点击div里面的按钮1,就不会触发div绑定时间test1()方法
2>事件捕获
网景公司提出的事件流叫事件捕获流。
事件捕获流的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件,针对上面同样的例子,点击按钮,那么此时click事件会按照这样传播:(下面我们就借用addEventListener的第三个参数来模拟事件捕获流)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<button>
<p>点击捕获</p>
</button>
</div>
<script>
var oP=document.querySelector('p');
var oB=document.querySelector('button');
var oD=document.querySelector('div');
var oBody=document.querySelector('body');
oP.addEventListener('click',function(){
console.log('p标签被点击')
},true);
oB.addEventListener('click',function(){
console.log("button被点击")
},true);
oD.addEventListener('click',
function(){
console.log('div被点击')
},true);
oBody.addEventListener('click',function(){
console.log('body被点击')
},true);
</script>
</body>
</html>
打印:
body被点击
div被点击
button被点击
p标签被点击
正如我们看到的,和冒泡流万全相反,从最不具体的元素接收到最具体的元素接收事件 body=>div=>button=>p
33.SPA单页面应用
SPA是什么?
SPA,即Single Page Application,按照字面意思就是单页面应用,通俗点就是整个网站由一个html页面构成。
三大框架Angular Vue React都是SPA
SPA的优点
页面响应速度快
减轻服务器压力
SPA的缺点
不利于SEO(Search Engine Optimization)搜索引擎优化
首屏打开速度很慢,因为用户首次加载需要先下载SPA框架及应用程序的代码,然后再渲染页面。
解决方法:
SSR(Server-Side Rendering)服务端渲染
简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序
SSR常用框架
React 的 Next
Vue.js 的 Nuxt
既然说到SSR就,说一下它的优缺点
优点:
1.更快的响应速度
2.容易被爬虫爬到页面数据
缺点:
1.增加服务器压力
2.开发难度增大
3.可能会由于某些因素导致服务器端渲染的结果与浏览器端的结果不一致
原理类的题目:
- Vue响应式是怎么实现的?
整体思路是数据劫持+观察者模式
高频CSS 问题:
最后
以上就是无语手机为你收集整理的2022VUE前端题,陆续更新中的全部内容,希望文章能够帮你解决2022VUE前端题,陆续更新中所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复