赞
踩
目录
11、css的引用有哪些,link和@import的区别?⭐
20、display: none 和 visibily: hidden 区别? ⭐⭐
19、 js中call、apply、bind有什么区别?⭐⭐
3. jQuery 里的 ID 选择器和 class 选择器有何不同?
4. 如何在点击一个按钮时使用 jQuery 隐藏一个图片?
5. $(document).ready() 是个什么函数?为什么要用它?
6. JavaScript window.onload 事件和 jQuery ready 函数有何不同?
8. jQuery 里的 each() 是什么函数?你是如何使用它的?
9. 你是如何将一个 HTML 元素添加到 DOM 树中的?
10. 你能用 jQuery 代码选择所有在段落内部的超链接吗?
11. $(this) 和 this 关键字在 jQuery 中有何不同?
12. 你如何使用 jQuery 来提取一个HTML 标记的属性,例如链接的 href?
14. jQuery 中 detach() 和 remove() 方法的区别是什么?
15. 如何利用 jQuery 来向一个元素中添加和移除 CSS 类?
16. 使用 CDN 加载 jQuery 库的主要优势是什么 ?
17. jQuery.get() 和 jQuery.ajax() 方法之间的区别是什么?
18. jQuery 中的方法链是什么?使用方法链有什么好处?
19. 你要是在一个 jQuery 事件处理程序里返回了 false 会怎样?
20. 哪种方式更高效:document.getElementbyId("Id") 还是 $("#Id")?
8、v-for 为什么加 key?不加 key 会怎么样?⭐⭐
9、v-for 写在 template 上,不能加 key 怎么办?
14、vue 里边如何让 css 样式只在当前组件中生效? ⭐
15、vue 的 watch 和 computed 有什么区别?他们的应用场景?⭐⭐⭐
18、vue 中使用 refs 获取组件的 dom 元素报 undefined 如何解决?⭐⭐⭐
20、Vue.extend 和 Vue.component 的区别?
21、Vue2 中为什么组件 date 只能是一个函数而不是一个对象?⭐⭐
24、vue 是如何实现双向数据绑定? (原理与缺陷)⭐⭐⭐
5、uniapp 上传文件时用到的 api 是什么? 格式是什么?
7、rpx、px、em、rem、%、vh、vw 的区别是什么?⭐
11、分别写出 jQuery、vue、小程序、uni-app 中的本地存储
12、JQ、VUE、uni-app、小程序的页面传参方式? ⭐
13、vue、微信小程序、uni-app 绑定变量属性区别?
3、cookie、sessionStorage、localStorage的区别?⭐⭐⭐
alt 是给搜索引擎识别,在图像无法显示时的替代文本。
title 是元素的注释信息,主要是给用户解读。
当鼠标放到文字或是图片上时有 title 文字显示。在 IE 浏览器中 alt 起到了 title 的作用,变成文字提示。
<header> | 定义文档的头部区域 |
<nav> | 定义导航链接 |
<article> | 内容标签 |
<section> | 定义文档某个区域 |
<aside> | 侧边栏标签 |
<footer> | 定义了文档的尾部区域 |
<figure> | 规定独立的流内容(图像、图表、照片、代码等) |
<figcaption> | 定义 <figure> 元素的标题 |
css 的引用有哪些:
link 和 @import 的区别:
rem:CSS3 中新增的一个相对长度单位,相对于根元素 <html> 的 font-size 字体大小,根元素字体大小未设置,使用浏览器默认字体大小。
vw:相对于视口的宽度。视口被均分为100单位的 vw。
vh:相对视口高度,视口被均分为100单位的 vh。
vmin:相对于视口宽度或高度中较小的那个。其中最小的那个被均分为100单位的 vmin。
vmax:相对于视口宽度或高度中较大的那个。其中最大的那个被均分为100单位的 vmax。
cm:厘米,绝对长度单位。
mm:毫米,绝对长度单位。
in:英寸,绝对长度单位。
%:百法比
应用场景:
vw、rem、em、rpx、%
设置浮动的图片,可以实现文字环绕图片。设置了浮动的块级元素可以排列在同一行。设置了浮动的行内元素可以设置宽高。浮动造成的影响:使盒子脱离文档流,如果父级盒子没有设置高度,需要被子盒子撑开,那么这时候父级盒子的高度就塌陷了,同时也会造成后面的盒子布局受到影响。
清除浮动,主要是为了解决父级元素因为子级浮动引起的内部高度为 0 的问题
- clearfix:after
- {
- content:"";
- display:block;
- visibility:hidden;
- height:0;
- line-height:0;
- clear:both;
- }
基本选择器:
CSS3新增选择器:
后代选择器 | ul li { } : 选择子类元素,包括间接子类 |
子代选择器 | ul>li { } :选择子类元素,只包括直接子类 |
相邻兄弟选择器 | div+p { } : 选择紧跟在 div 元素后面的 p 元素 |
通用兄弟选择器 | div~p { } : 选择 div 元素后面的所有 p 元素 |
共享选择器 | div1,div2 { } :选择所有元素 |
!important >> 内联样式 >> id 选择器 >> 类选择器/伪类选择器/属性选择器 >> 标签选择器/后代选择器/伪元素选择器 >> 子选择器/相邻选择器 >> 通配符 * >> 继承样式 >> 浏览器默认样式
position:relative:相对定位,相对于自己进行定位。
position:absolute:绝对定位,相对于有相对定位的父级元素进行定位,没有就找 body。
- <style>
- .box {
- position: absolute;
- width: 100px;
- height: 100px;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- }
- </style>
- <style>
- .box {
- width: 400px;
- height: 300px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 1px solid black;
- }
- .child {
- width: 200px;
- height: 150px;
- background-color: red;
- }
- </style>
- <body>
- <div class="box">
- <div class="child"></div>
- </div>
- </body>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- <style>
- .box {
- width: 400px;
- height: 300px;
- display: table-cell;
- text-align: center;
- vertical-align: middle;
- border: 1px solid black;
- }
- .child {
- width: 200px;
- height: 150px;
- background-color: red;
- display: inline-block;
- }
- </style>
- <body>
- <div class="box">
- <div class="child"></div>
- </div>
- </body>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
JS 的数据类型分为两类,分别是基本数据类型和引用数据类型。它们主要区别是在内存中的存储方式不同。
JS 的变量都储存到内存中,内存中开辟了两个区域储存变量,分别是栈区域和堆区域。 栈与堆实际上是操作系统对进程占用的内存空间的两种管理方式。
栈:
堆:
栈和堆的优缺点:
浅克隆:
深克隆:
存在问题?怎么优化?
虽然浏览器可以自动的进行垃圾回收,但是当代码比较复杂时,垃圾回收对性能的消耗比较大,所以应该尽量减少垃圾回收。需要根据具体应用的需求和环境进行优化。
什么是闭包?
因为作用域链的存在,函数的内部可以直接读取全局变量,而函数内部无法读取另一个函数内部的局部变量,如果想读取函数内部的局部变量,可以通过闭包来实现。闭包就是在一个函数内部创建另外一个函数,让你可以在一个内层函数中访问到外层函数的局部变量。简单来说,闭包就是可以读取其他函数内部局部变量的函数,本质上,闭包是将函数内部和函数外部连接起来的桥梁。
为什么要使用闭包?
闭包的作用?
闭包的缺点?
由于垃圾回收器不会将闭包中变量销毁,于是就造成了内存泄露,内存泄露积累多了就容易导致内存溢出。如何解决:在销毁函数之前,将不使用的局部变量全部删除。
闭包的应用?
JS继承的方法有以下几种:原型链继承、构造函数继承、组合继承、原型式继承和寄生式继承,寄生组合式继承,ES6 Class实现继承。继承的目的是:重复利用另外一个对象的属性和方法。
原型链继承:将父类的实例作为子类的原型,从而实现对父类属性和方法的继承。优点:写法方便简洁,容易理解。缺点:不能传递参数和共享所有继承的属性和方法,当一个发生改变另外一个随之改变。
构造函数继承:在子类的构造函数中调用父类的构造函数,使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上,从而实现对父类实例属性的继承。优点:解决了原型链继承不能传参的问题和父类的原型共享的问题。缺点:方法都在构造函数中定义,因此无法实现函数复用。
组合继承:将原型链继承和构造函数继承结合起来,既可以实现对父类原型属性和方法的继承,又可以实现对父类实例属性的继承。优点: 解决了原型链继承和构造函数继承造成的影响。缺点: 无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
原型式继承:通过创建一个临时构造函数来实现对父类的属性和方法的继承。优点:不需要单独创建构造函数。缺点:属性中包含的引用值始终会在相关对象间共享。
寄生式继承:在原型式继承的基础上,通过在临时构造函数中添加方法和属性,从而实现对父类的继承。优点:写法简单,不需要单独创建构造函数。缺点:通过寄生式继承给对象添加函数会导致函数难以重用。
寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。优点:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要,多余的属性。与此同时,原型链还能保持不变。缺点:代码复杂。
ES6 Class实现继承:ES5 的继承,实质是先创造子类的实例对象 this,然后再将父类的方法添加到 this 上面 (Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法加到 this 上面 (所以必须先调用super方法),然后再用子类的构造函数修改 this。需要注意的是,class 关键字只是原型的语法糖,JS继承仍然是基于原型实现的。 优点:语法简单易懂,操作更方便。缺点:并不是所有的浏览器都支持 class 关键字 lass Person。
- // 手写 new 操作符
- function mockNew(constructor, ...args) {
- // 1.创建一个新对象 obj
- const obj = {};
- // 2.把构造函数当参数传入,新对象指向构造函数原型对象
- obj.__proto__ = constructor.prototype;
- // 3.通过 apply 将构建函数的 this 指向新对象
- let result = constructor.apply(obj, args);
- // 4.根据返回值判断
- return result instanceof Object ? result : obj;
- }
数组的基本操作方法:
查找方法:
数组类的静态方法:
数组填充:
迭代方法:
修改原数组:push、pop、shift、unshift、splice、reverse、sort、fill。
不修改原数组:slice、concat、indexOf、lastIndexOf、join、toString、filter、every、some、forEach、map、find、findIndex。
事件处理函数:在事件处理函数中,this 指向触发事件的目标对象。
定时器:定时器中的 this,指向的是 window。
commonjs、es6、amd、cmd
原生操作DOM元素:
vue操作DOM元素:
- //防抖和节流函数都是用于防止事件高频率的重复触发
- //防抖: 在一定时间内,如果方法没用再次被触发,则执行最后一次
- <body>
- <button>点我</button>
- <script>
- var btn = document.querySelector("button");
- var tiemr = null;
- btn.onclick = function () {
- clearInterval(tiemr);
- tiemr = setTimeout(() => {
- console.log("我触发了")
- }, 500)
- }
- </script>
- </body>
-
- //节流:在规定时间内只只执行一次或数次
- <body>
- <button>按钮</button>
- <script>
- var btn = document.querySelector("button");
- var jie = true;
- btn.onclick = function() {
- if(jie) {
- jie = flase;
- console.log('发送了请求');
- setTimeout(()=>{
- jie = true;
- },2000)
- }
- }
- </script>
- </body>
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
JQ 是函数库,本质上还是操控 JS,只不过更简便了。vue 是 mvvm 框架,核心是双向数据绑定,
一般情况下不需要操控 DOM 元素,而是操控数据为主。
跨平台:TypeScript 编译器可以安装在任何操作系统上,包括 Windows、Linux 和 macOS。
面向对象的语言:TypeScript 提供所有标准的 OOP 功能,如类、接口和模块。
静态类型检查:TypeScript 使用静态类型并帮助在编译时进行类型检查。可以在编写代码时发现编译时错误,而无需运行脚本。
可选的静态类型:如果你习惯了 JavaScript 的动态类型,TypeScript 还允许可选的静态类型。
ES6 特性:TypeScript 包含计划中的 ES6 的大部分特性,例如箭头函数。
DOM 操作:您可以使用 TypeScript 来操作 DOM 以添加或删除客户端网页元素。
TypeScript 更具表现力,这意味着它的语法混乱更少。
由于高级调试器专注于在编译时之前捕获逻辑错误,因此调试很容易。
静态类型使 TypeScript 比 JavaScript 的动态类型更易于阅读和结构化。
由于通用的转译,它可以跨平台使用,在客户端和服务器端项目中。
number:表示数字类型,包括整数和浮点数。
string:表示字符串类型,用于表示文本数据。
boolean:表示布尔类型,只有两个可能的值:true 和 false。
null: 空值。
undefined:未定义的值。
object:表示非原始类型的对象,可以是任意结构的对象。
array:表示数组类型,可用于存储多个相同类型的元素。
tuple:表示元组类型,用于表示具有固定数量和特定顺序的元素组合。
enum:表示枚举类型,用于定义一组命名的常量值。
any:表示动态类型,可以接受任何类型的值。
void:表示空类型,没有任何返回值的类型。
never:表示永远不存在的类型,通常用于表示永远不会返回的函数的返回类型。
unknown:表示未知类型,类似于 any,但对类型安全要求更严格。
当前的稳定版本是 4.2.3。
接口为使用该接口的对象定义契约或结构。接口是用关键字定义的 interface,它可以包含使用函数或箭头函数的属性和方法声明。
- interface IEmployee {
- Code: number;
- Name: string;
- getSalary: (number) => number;
- getName(number): string;
- }
let、const、结构赋值、class 类、箭头函数、map、set、promise、async await(es7)、扩展运算符...、Module 模块化。
set:
ES6 提供新的数据结构 set,它类似于数组,但是成员的值都是唯一的,没有重复的值。可以用来做数组去重,但是 set 是伪数组,可以通过 Array.from() 或者扩展运算符...转换成数组。Set 结构没有键名,只有键值 (或者说键名和键值是同一个值)。可以使用 keys()、values()、entries()、forEach() 方法遍历成员,使用 for..of... 循环遍历 Set。如果想直接在遍历操作中改变原来的 Set 结构,可以利用原 Set 结构映射出一个新的结构,然后赋值给原来的 Set 结构,或者使用 Array.from 方法。
实例操作方法: size、add、delete、has、clear。
Map:
"键值对" 的数据结构,可以实现数组重组。JavaScript 对象 object 本质上是键值对的集合,缺陷是只能使用字符串作为键,而 map 结构优化了这个缺陷,它提供了 "值-值" 对的形式,让键名不再局限于字符串,是一种更完善的 Hash 结构实现。简单来说:Map 类似于对象,也是键值对的集合,但是 "键" 的范围不限于字符串, 各种类型的值(包括对象)都可以当作键。遍历方法:keys( )、values( )、entries( )、forEach( )、for..of...。注意:由于一个 key 只能对应一个 value,所以多次对一个 key 放入 value,后面的值会把前面的值冲掉。
实例操作方法:size、set、get、has、delete、clear。
Set 和 Map 的区别:
适用场景:简单的函数表达式,内部没有 this 引用,没有递归、事件绑定、解绑定,适用于 map、filter 等方法中。
变量提升是指 JS 的变量和函数声明会在代码编译期,提升到代码的最前面。 变量提升成立的前提是使用 Var 关键字进行声明的变量,并且变量提升的时候只有声明被提升,赋值并不会被提升,同时函数的声明提升会比变量的提升优先。
- function fn1() {
- console.log(1);
- }
- function fn2() {
- console.log(2);
- }
- setTimeout(()=>{
- fn1()
- },2000)
-
- fn2()
-
- 1、先执行完fn2再执行fn1,因为当主线程遇到异步任务的时候,会把异步任务放进 "任务队列" 里,
- 执行完同步任务后,再循环的去检查任务队列里面有哪些异步任务要执行。
- 2、这是一个异步,因为他是分开执行的,并没有同时执行。
- 3、如果想要让它变成同步执行,执行完fn1后再执行fn2,可以使用异步函数,把异步变成同步执行。
- 有三种方法可以实现,分别是回调函数、promise、async await。
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
同步和异步的区别? 同步函数和异步函数的区别?
js 代码的执行顺序?
js 是单线程语言,同一个时间只能做一件事,执行顺序是由上往下执行的,这样很容易造成阻塞,所以把任务分成了同步任务和异步任务两种。当主线程遇到异步任务,比如说计时器或者 ajax 请求回调问题,就把异步任务放进 "任务队列" 里,执行完同步任务后,再循环的去检查任务队列里面有哪些异步任务要执行。这是一个异步执行,分开来执行的,如果想要变成同步执行,比如说等到计时器执行完后再执行或者等请求服务器响应后再继续运行,可以使用异步函数,把异步执行变成同步执行。
异步函数实现?
回调函数具体实现:
- function fn1(cb) {
- console.log(1);
- cb();
- }
- function fn2() {
- console.log(2);
- }
- setTimeout(()=>{
- fn1(fn2)
- },2000)
-
- // 事件堆栈 宏观 微观
- 先分析宏观,解析fn1和fn2,但是他们还没有执行,执行计时器,2秒后执行fn1进入微观里面
- 执行打印,然后再执行cb回调函数,执行fn2。
promise 具体实现:
- function fn1() {
- return new Promise((resolve))=>{
- console.log(1);
- resolve()
- }
- }
- function fn2() {
- console.log(2);
- }
- setTimeout(()=>{
- fn1().then(()=>{
- fn2()
- })
- },2000)
通过 promise 构造函数 new 一个实例,promise 构造函数接收一个函数作为参数,这个函数有两个参数, 分别是成功回调 resolve 和失败回调 reject。在异步操作成功时调用 resolve,并将结果作为参数传递出去,在异步操作失败时调用 reject,并将错误作为参数传递出去。根据 promise 状态,成功时执行 .then,失败时执行 .catch,并接收对应的参数执行相应的处理。一般把成功的处理逻辑写在 .then()里,把失败的处理逻辑写在 .cache() 里。then 方法返回的是一个新的 Promise 实例,因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法,把回调地狱转为链式编程。
async await 具体实现:
- function fn1() {
- return new Promise((resolve)=>{
- console.log(1);
- resolve(1);
- }
- }
- function fn1() {
- return new Promise((resolve)=>{
- console.log(2);
- resolve(2);
- }
- }
- function fn1() {
- console.log(3);
- }
-
- setTimeout(async ()=>{
- let res1 = await fn1();
- let res2 = await fn2();
- fn3();
- },2000)
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
async await 基于 promise 实现的,async 写在方法前面,用于声明一个 function 是异步的,async 和 await 是配对使用的,await 只能写在 async 的内部,await 后面跟着的是一个 promise 对象,async 执行期间一旦遇到 await,会等里面的 Promise(异步)执行完毕再执行后面的代码,如果是 reject 状态,可以使用 try-catch 捕捉。
promise 和 async await 区别:
相同点:promise 和 async await 都是异步编程的优化和解决方案。
不同点:
题目1:输出执行顺序
- async function async1() {
- console.log('1');
- await async2();
- console.log('2');
- }
- async function async2() {
- new Promise(function(resolve) {
- console.log('3');
- resolve();
- }).then(function() {
- console.log('4');
- });
- }
- console.log('5');
-
- setTimeout(function() {
- console.log('6');
- }, 0)
-
- async1();
-
- new Promise(function(resolve) {
- console.log('7');
- resolve();
- }).then(function() {
- console.log('8');
- });
-
- console.log('9');
-
- // 5 1 3 7 9 4 2 8 6
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
解析:
1、遇到两个定义 async 的函数,继续往下走,遇到 console 语句,直接输出 5。
2、继续向下执行,遇到 async1() 函数,async 函数中在 await 之前的代码是立即执行的, 所以输出 1,然后执行 async2() 函数,输出 3,把 console.log('2') 放到事件队列里。
3、继续向下执行,遇到 Promise,Promise 中的代码是被当做同步任务立即执行的,所以 输出 7,然后执行 resolve,将 .then 里面的分配到事件队列中。
4、最后输出 9,至此主线程上的宏观任务执行完毕,开始查找清空微任务队列。
5、微观任务队列里有三个任务,先执行 async2 里面的 .then,输出 4,再执行 async1 里面的 console.log(2) 输出 2,然后再执行 8,事件队列里的也执行完了。
6、第二轮循环宏观任务开始,此时宏任务中只有一个 setTimeout,取出直接输出即可 6。
题目2:输出执行顺序
- sync function async1() {
- console.log('1');
- await async2();
- //更改如下:
- setTimeout(function() {
- console.log('2')
- },0)
- }
- async function async2() {
- //更改如下:
- setTimeout(function() {
- console.log('3')
- },0)
- }
- console.log('4');
-
- setTimeout(function() {
- console.log('5');
- }, 0)
- async1();
-
- new Promise(function(resolve) {
- console.log('6');
- resolve();
- }).then(function() {
- console.log('7');
- });
- console.log('8');
-
- // 4 1 6 8 7 5 3 2
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
题目3:输出执行顺序
- async function async1() {
- console.log('1')
- await async2()
- console.log('2')
- }
- async function async2() {
- console.log('3')
- }
-
- console.log('4')
-
- setTimeout(() => {
- console.log('5')
- }, 0)
-
- Promise.resolve().then(() => {
- console.log('6')
- })
-
- async1()
-
- let promise2 = new Promise((resolve) => {
- resolve('7')
- console.log('8')
- })
-
- promise2.then((res) => {
- console.log(res)
- Promise.resolve().then(() => {
- console.log('9')
- })
- })
- console.log('10')
-
- // 4 1 3 10 6 2 8 7 9 5
- // 解析:6 也是被分配到任务队列中,而且是在 async1 前执行的,所以主线程结束后先执行。
- // promise2 会直接输出,'resolve'不同于'await',不会阻止后面的执行,.then 才会阻止。
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
$() 函数是 jQuery() 函数的别称。$() 函数用于将任何对象包裹成 jQuery 对象,接着你就被允许调用定义在 jQuery 对象上的多个不同方法。你甚至可以将一个选择器字符串传入 $() 函数,它会返回一个包含所有匹配的 DOM 元素数组的 jQuery 对象。
jQuery 支持不同类型的选择器,例如 ID 选择器、class 选择器、标签选择器等。你可以用标签选择器来选择所有的 div 元素。jQuery 代码:$("div"),这样会返回一个包含所有 5 个 div 标签的 jQuery 对象。
ID 选择器使用 ID 来选择元素,比如 #element1,而 class 选择器使用 CSS class 来选择元素。当你只需要选择一个元素时,使用 ID 选择器,而如果你想要选择一组具有相同样式的 class 元素,就要用 class 选择器。
- $('#ButtonToClick').click(function(){
- $('#ImageToHide').hide();
- });
ready() 函数用于在文档进入 ready 状态时执行代码。当 DOM 完全加载,jQuery 允许你执行代码。使用 $(document).ready() 的最大好处在于它适用于所有浏览器,jQuery 帮你解决了跨浏览器的难题。
你能用下面的 jQuery 选择器获取所有具备 multiple=true 的 <select > 标签的选中项:结合使用了属性选择器和 :selected 选择器,结果只返回被选中的选项。
$('[name=NameOfSelectedTag] :selected')
each() 函数允许你遍历一个元素集合。你可以传一个函数给 each() 方法,被调用的 jQuery 对象会在其每个元素上执行传入的函数。应用场景:如何在 alert 框里显示所有选中项。可以用上面的选择器代码找出所有选中项,然后我们在 alert 框中用 each() 方法来一个个打印它们。
- $('[name=NameOfSelectedTag] :selected').each(function(selected) {
- alert($(selected).text());
- });
可以用 jQuery 方法 appendTo() 将一个 HTML 元素添加到 DOM 树中。这是 jQuery 提供的众多操控 DOM 的方法中的一个。你可以通过 appendTo() 方法在指定的 DOM 元素末尾添加一个现存的元素或者一个新的 HTML 元素。
- <p id=“text”>
- <a href="#">a1</a>
- <p>
- <a href="#">a2</a>
- <a href="#">a2</a>
- </p>
- </p>
-
- $(’#text a’); // 查出来a1,a2,a3
- $(’#text>a’); // 查出来a1
$(this) 返回一个 jQuery 对象,你可以对它调用多个 jQuery 方法,比如用 text() 获取文本,用 val() 获取值等等。而 this 代表当前元素,它是 JavaScript 关键词中的一个,表示上下文中的当前 DOM 元素,你不能对它调用 jQuery 方法。
attr() 方法被用来提取任意一个 HTML 元素的一个属性的值。
- $('a').each(function(){
- alert($(this).attr('href'));
- });
attr() 方法也可以在调用的时候带上一个值,给当前属性赋值。例如:attr(name, value);
都可以移除一个DOM元素。区别:
通过利用 addClass() 和 removeClass() 这两个 jQuery 方法。动态的改变元素的 class 属性可以使用类 .active 来标记它们的未激活和激活状态。
除了报错节省服务器带宽以及更快的下载速度这之外,最重要的是,如果浏览器已经从同一个 CDN 下载类相同的 jQuery 版本, 那么它就不会再去下载它一次。
方法链是对一个方法返回的结果调用另一个方法。这使得代码简洁明了,同时由于只对 DOM 进行了一轮查找,性能方面更加出色。
这通常用于阻止事件向上冒泡。
第一种,因为它直接调用了 JavaScript 引擎。
指令的本质:语法糖。在编译阶段 render 函数里,会把指令编译成 JavaScript 代码
v-if:通 过 true 和 fal se 控制元素是否需要被渲染
v-else:搭配 v-if 使用,不需要表达式,当 vi-if 为 false 时才被渲染出来
v-show:通过 true 和 false 控制元素是否显示或隐藏
v-model:实现表单控件和数据的双向绑定(<input>、<select>、<textarea>、components)
v-bind:动态绑定元素属性
v-on:简写@,事件绑定
v-text:渲染字符串,会覆盖原先的字符串
v-html:渲染 Html,{{}} 和 v-text 都是输出文本,v-html 输出 Html (XSS攻击)
v-once:只渲染元素和组件一次,当数据发生改变时,不会再变化(用于优化更新性能)
v-slot:定义一个具名插槽或作用域插槽。可缩写为 #
Vue 中使用 v-model 指令来实现表单控件和数据的双向绑定
,
将表单中用户提交的信息和设定的变量进行绑定。
v-model 其实是一个语法糖,他本质上是包含两个操作:
注意:用户信息不一定与 value 值绑定
相同的是:都是条件渲染指令,通过 true 和 false 控制元素的显示和隐藏。
不同的是:
v-if 当条件为 true 时, 把元素创建并渲染到 Html,为 false 时把元素删除,不会渲染到 Html 上。是一个创建和删除的过程,删除时并不会占用空间位置。
v-shou 无论是 true 还是 false 元素都被渲染出来,当条件为 false 时通过 display: none 控制元素隐藏。是一个显示和隐藏的过程,隐藏时还是会占用空间位置。
应用场景:
什么是虚拟 DOM?
虚拟 DOM 是怎么更新数据的?
虚拟 DOM 可以很好的跟踪当前 DOM 的状态,他会根据当前数据生成一个描述当前 DOM 的虚拟 DOM,然后数据改变的时候又会生成一个新的虚拟 DOM,然后通过 diff 算法计算出前后两个虚拟DOM 之间的差异,得出一个最优的更新方法。
虚拟 DOM 是怎么生成的?
首先代码运行会走生命周期,当生命周期走到 created 到 beforeMount 之间的时候,会编译 template 模板成 render 函数。然后在 beforeMount 和 mounted 之间执行 render 函数。当 render 函数运行时 h 函数会被调用,而 h 函数最主要的就是执行了 vnode 函数,vnode 函数主要作用就是将 h 函数传进来的参数转换成 js 对象,即生成虚拟 DOM。之后当数据发生改变时会重新编译生成一个新虚拟 DOM (vdom),然后通过 diff 算法计算出前后两个虚拟 DOM 之间的差异,得出一个最优的更新方法。从而减少了不必要的 DOM 操作,提高了页面的渲染速度和性能。
对 Diff 算法的了解?
简单来说,实现 diff 算法的过程,就是一个执行 patch 函数,patchVnode 函数,updateChildren 函数……这样的一个循环递归的过程。(patch 只执行一次)
真实 DOM 的优缺点
优点是易用,缺点是效率低:解析速度慢,内存占用高。性能差:频繁操作真实 DOM,容易导致重绘和回流。
虚拟 DOM 的优缺点
优点:
缺点:
什么是就地复用策略?
就地复用策略是 Vue 在 DOM 更新时采用的一种优化方式。在更新现有 DOM 树时,Vue 会尽可能地复用已存在的 DOM 元素,而不是删除并重新插入。这样可以减少不必要的 DOM 操作,提高性能。
Vue 在执行 DOM 更新时会进行四个步骤:
在第二步中,Vue 会对比新旧虚拟 DOM 树的节点,找出它们之间的差异。对于相同的节点,在更新时 Vue 会尽可能地复用已存在的 DOM 元素。这样做可以避免不必要的 DOM 操作,提高性能。就地复用策略只适用于同一层级的元素之间进行比较。如果两个元素的父元素不同,Vue 会直接删除旧元素并在新父元素中创建新元素。
key 是什么?
唯一标识。
为什么要在 v-for 上加 key?
v-for 中加上 key 是为了提高列表的渲染性能和提供更好的更新策略。
不加 key 会怎么样?key 有什么用?
什么是钩子函数?什么是生命周期?
vue2 的生命周期有哪些?
注意:mounted 和 updated 不会保证所有的子组件都被挂载或重新渲染,如果希望等到整个视图都渲染完毕再执行某些操作,可以在 mounted 或 updated 内部使用 $nextTick 函数。
父子组件生命周期执行顺序?
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
vue 生命周期的作用是什么?
vue 的生命周期中有多个事件钩子,通过不同阶段对应不同的钩子函数来实现组件数据管理和 DOM渲染两大功能。
第一次页面加载会触发哪几个钩子?
beforeCreate,created,beforeMount,mounted
如果加入了 keep-alive 多两个生命周期:
activated,deactiated
如果加入了 keep-alive ,第一次进入组件会执行那些生命周期?
beforeCreate,created,beforeMount,mounted,activated
如果加入了 keep-alive,第 n 次进入组件会执行那些生命周期?
只执行 activated
创建后和渲染后有什么区别?
created 是实例创建完成后调用,只能访问 data、computed、watch、methods 上的方法和数据,未挂载 dom,还不能获取 dom 节点,如果要进行 dom 操作,那就要用 $nextTick 函数。常用于简单的 ajax 请求。不能访问到 el 属性。mounted 是实例被挂载后调用,vue 实例已经初始化完成了,已经可以获取 dom 节点和操作 dom 节点了。可以访问 el 属性。
渲染后和更新后有什么区别?
updated 与 mounted 不同的是,在每一次的 DOM 结构更新 vue 都会调用一次 updated() 钩子函数!而 mounted 仅仅只执行一次而已。
简述每个周期具体适合哪些场景?
Vue2 和 Vue3 生命周期有什么区别?
Vue2生命周期 | Vue3生命周期 |
---|---|
beforeCreate | setup |
created | created |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmounted |
destroyed | onUnmounted |
activated | onActivated |
deactivated | onDeactivated |
errorCaptured | onErrorCaptured |
全局生命周期:
页面生命周期:
组件生命周期:
uniapp 生命周期是以小程序生命周期为基础实现的,分为应用生命周期、页面生命周期、组件生命周期。 其中组件生命周期就是 vue 生命周期。
应用生命周期:
页面生命周期:
组件生命周期:
uniapp 的组件生命周期和 Vue 标准组件生命周期相同。在当前版本的 uniapp中,你既可以选择使用 vue2 进行开发,也可以使用 vue3 进行开发,可以参考 vue2 和 vue3 的生命周期。
在组件中的 style 前面加上 scoped 就可以了。
应用场景
$nextTick 是什么?
事件轮询,把所有的触发事件都放在一个事件栈里 (事件队列),再根据实际情况先后执行。
$nextTick 有什么作用?
$nextTick 的原理?
$nextTick 本质是返回一个 Promise 对象。
$nextTick 的应用场景?
beforeCreated,Created,beforeMount。在 mounted 这个阶段挂载后才能操作 DOM 节点,要想在 Created 阶段操作 DOM 节点,可以将获取节点的操作放在 $nextTick 中,在 DOM 下一次更新完成后延迟回调。
问题:用 ref 加在普通元素上,可以通过 this.$refs.name 获取到 dom元素。用 ref 注册子组件,父组件可以通过 this.$refs.name 调用子组件里的函数。在页面初始化的时候调用 this.$refs.name 的时候提示 undefined。
主要有以下几种情况以及解决方案:
原因一:在 created 钩子函数中调用,created 在实例创建完成后被立即调用,这个时候还不能操作 DOM 节点。
解决方案:在 mounted 阶段挂载后执行。
原因二:ref 组件使用了条件渲染,即 v-if,v-show,这些 DOM 节点无法在 mounted 中访问。因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们,它们还不存在。ref 也不是响应式的,所有动态加载的模板更新它都无法相应的变化。
解决方案:①不在 mounted 中获取元素,在 updated 中获取。②调用 Vue 的全局 api:$nextTick 延迟到 DOM 下一次更新后执行,在渲染完成后获取 ref。
原因三:使用了 v-for 循环动态绑定 ref,this.$ref.name 获取的是数组。
解决方案:由 this.$refs.name 改为 this.$refs.name[index]。
问题1:vue 无法检测实例被创建时不存在于 data 中的变量
原因:由于 vue2 双向数据绑定的核心原理 Object.defineProperty 数据劫持只能劫持对象的属性,因此在初始化时要对所有的已有属性进行遍历,也就是在初始化实例时通过 Object.defineProperty 劫持 data 中各个属性的 getter/setter,所以变量必在 data 对象上存在才能让 Vue 将它转换为响应式的。
解决方法:把变量放到 data 里面。
问题2:vue 无法检测到 data 中对象,数组的动态添加和删除,不能通过索引直接修改或者赋值,也不能修改数组的长度
原因:vue2 是通过 Object.defineProperty 数据劫持 结合 订阅发布模式 实现双向数据绑定的。通过 Object.defineProperty 来劫持各个已有属性的 getter 和 setter,它不能劫持整个对象,只能劫持已有对象属性,所以只能监听到已有数据是否被修改,不能监听到对象的新增删除属性,而且无法监控到数组下标的变化,引入不能修改数组长度。
解决方法:通过 this.$set 动态添加,通过 this.$delete 动态移除。通过 Object.assign({},{}) 合并对象并返回新对象和数组。通过 push、pop、shift、unshift、splice、sort、reverse 等直接改变原数组的方法会触发更新。
问题3:异步获取接口数据,DOM 数据不发现变化
原因:Vue 在更新 DOM 时是异步执行的。在修改数据后视图不会立刻更新,而是等同一事件循环中的所有数据修改完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取 DOM,获取的仍是未修改的 DOM。
解决方法:可以在数据变化之后立即使用 $nextTick,这样回调函数将在 DOM 更新完成后被调用,可以获取更新后的 DOM,$nextTick 解决了异步渲染获取不到更新后 DOM 的问题。
问题4:循环嵌套层级太深,视图不更新
原因:当嵌套太深时,页面也可能不更新,此时可以让页面强制刷新。
解决方法:可以让页面强制刷新,this.$forceUpdate (不建议用)
问题5:路由参数变化时,页面不更新(数据不更新)
原因:路由视图组件引用了相同组件时,当路由参会变化时,会导致该组件无法更新,也就是我们常说中的页面无法更新的问题。路由切换时页面只会渲染第一次路由匹配到的参数。
解决方法:通过 watch 监听 $route 的变化。给 <router-view> 绑定 key 属性,这样 Vue 就会认为这是不同的<router-view>。弊端:跳转到某些路由下没有这个问题,key 属性是多余的
区别:
extend 的基础用法:
使用基础 Vue 构造器函数,创建一个子类,参数是一个包含组件选项的对象。然后 new 一个实例并通过 $mount 挂载到特定的元素上,就可以把这个实例 append 到页面 body 里。
extend 的应用场景:
Vue.extend 属于 Vue 的全局 API,在实际业务开发中我们很少使用,因为相比常用的 Vue.component 写法,使用 extend 步骤要更加繁琐一些。但是在一些独立组件开发场景中,Vue.extend + $mount 这对组合是我们需要去关注的。比如:如 alert 弹窗组件,你肯定希望 alert 可以动态插入到 body 中,而不需要在 dom 文档流中放一个莫名其妙的 alert,大部分时间他还是隐藏的。
简单来说,Vue 是一款渐进式 JavaScript 框架,用于构建用户界面。综合了 Angular 的模块化和 React 的虚拟 DOM 的优点。采用了 MVVM 的设计模式,实现了双向数据绑定。通过数据驱动和组件化的开发方式,使得前端开发变得更加简单、高效。
vue 核心概念(优点):
什么是数据双向绑定?
Vue 框架采用的是 mvvm 模式,实现了双向数据绑定,当数据发生改变时,立即触发视图的更新。当用户操作视图时,数据也会相应地进行更新。
vue2 是如何实现双向数据绑定的?
原理:
vue2 是通过 Object.defineProperty 数据劫持 结合 订阅发布模式 实现双向数据绑定的。通过 Object.defineProperty 来劫持各个属性的 getter 和 setter,当数据对象的属性被读取或修改时,会触发相应的 getter 和 setter 函数。当数据发生变化时,触发 setter 函数会通知相应的 Dep 调度器,Dep 调度器通知相应的订阅者,让订阅者执行自己的 update 逻辑进行更新视图。
缺点:
vue3 是如何实现双向数据绑定的?
原理:
Vue3 是通过 Proxy 数据代理 来实现的数据双向绑定,Proxy 是 ES6 中新增的一个特性,可以劫持整个对象,并返回一个新对象。实现过程是当一个普通的 javaScript 对象传入 vue 实例的时候,vue 会使用 Proxy 对象包装该对象,并在外界访问和修改对象属性时进行拦截。当属性发生改变的时候,vue 就能捕获到变化并更新相应的视图。ES6 提供 Proxy 构造函数,用来生成 Proxy 实例,接收两个参数 target 和 handler。target 是用 Proxy 包装的被代理对象,可以是任何类型的对象,包括原生数组,函数,甚至是另外一个代理。handler 是一个对象,其声明了代理 target 的一些操作,当任何一个对象属性发生变化时,就会触发 handler 中的 set 方法,从而更新对应的DOM节点。
优点:
缺点:存在兼容性问题,IE 无法兼容,vue2 兼容到了 IE8,如果不考虑兼容 IE 浏览器,可以考虑使用 vue3。
订阅发布模式是一种软件设计模式,其原理是基于一个中心的事件调度器 (或者称为消息队列)。 组件可以订阅感兴趣的事件,当事件发生时,调度器会通知所有订阅了该事件的组件进行相应的处理。
组成和具体实现:
observer 发布者:通过 Object.defineProperty 来劫持各个属性的 getter 和 sette,对数据进行监听。读取数据时 (绑定数据),触发 getter 添加订阅者 watcher 到调度器 Dep。当数据发生变化时,触发 setter 函数会通知相应的调度器 Dep。简单来说,发布者负责监听和发布事件。当某个事件发生时,发布者会将事件发布到调度器中。
Watcher 订阅者:当订阅的值/事件发生变化时,会接收到来自 Dep 订阅者的通知,从而触发回调函数。简单来说,订阅者可以感兴趣的事件。订阅者通过向调度器注册自关注的某个事件,以便在事件发生时接收通知,并执行相应的处理逻辑。(v-model,{{}},v-bind)
Dep 调度器:负责接收发布者发布的事件,并将事件分发给所有订阅了该事件的订阅者。收集订阅者 Watcher,每个属性拥有自己的 Dep 调度器,用于存放所有订阅了该属性的订阅者。当数据发生改变时,会遍历订阅者列表,通知所有的订阅者,让订阅者执行自己的 update 逻辑。
优点:
1、Vue2 只支持一个根节点,Vue3 支持多个根节点。
2、生命周期发生了改变 。
3、Vue2 使用的是选项式 api (optionsApi),Vue3 使用的是组合式 api (CompositionApi)。
4、核心原理不同
5、父子传参不同,setup 函数特性
MV系列框架中,M和V分别指Model层和View层。Model层是数据模型,用来存储数据。View层是视图,展示Model层的数据。在不同的框架中,可能会有所差别,但主要变的是数据的传输方式。
MVC(Model-View-Controller)(JavaEE 中的 SSH 框)
MVP(Model-View-Presenter)(Android)
MVC 是模型-视图-控制器:MVC 是单向通信,必须通过 Controller 来承上启下。Controller 不会更新 view 的数据,view 依赖于 model,通过监听 model 层数据变化自动更新。在 model 发生改变时,需要手动的去更新 view。MVC 是 dom 驱动的,大量操作 dom 使页面渲染性能降低,使加载速度变慢,影响用户体验。
MVC 执行步骤:用户输入 => 被 Controller 层拦截 => Controller 调用 Model 进行业务逻辑处理 / Controller 通知 View 描画页面 => Model 将结果反馈给 View =>View 描画页面
MVP 是模型-视图-表示器:MVP 是从 MVC 模式演变而来的,将 Controller 改名为 Presenter 的同时改变了通信方向,各部分之间的通信是双向的。view 不能直接访问 model,要通过 Presenter 层提供的接口,然后 Presenter 层再去访问 model 层。没有绑定数据,所有数据都需要在 Presenter 层进行手动同步。由于 view 层和 model 层都需要经过 Presenter 层,所有的交互都发生在 Presenter 内部,导致 Presenter 层比较复杂,维护起来也会有一定的问题。
MVP 执行步骤:用户输入(View需要展示某些数据) => 通知 Presenter 加载数据 => Presenter 层会调用 Model 层请求数据 => Model 层数据加载成功后通过回调方法通知 Presenter 层数据加载情况 => Presenter 层再调用 View 层的接口将加载后的数据展示给用户。
MVVM(Model-View-ViewModel) (vue \ react \ angular)
MVVM 是模型-视图-视图模型:MVVM 是双向数据绑定,是响应式的。view 和 model 之间没有直接的关系,通过 viewModel 来完成数据双向绑定,视图和数据自动同步更新。mvvm 是数据驱动的,避免了大量操作 dom。
如何实现双向数据绑定的?
vue2 是通过 Object.defineProperty 数据劫持 结合 订阅发布模式 实现双向数据绑定的。Vue3 是通过 Proxy 数据代理 来实现的数据双向绑定的。当数据发生改变的时候视图会同步更新,当用户操作视图的时候数据也会相应的更新。
MVVM 缺点
什么是 VueX、状态管理?
VueX 状态管理实现原理?
把多个组件需要共享的变量全部储存在一个对象里面,然后将这个对象放在顶层的 Vue 实例中,让其他组件可以使用,并且让这个对象里面的属性做到响应式。
VueX 的核心概念?(五个状态)
vuex 的优点?
vuex 的缺点?
刷新浏览器,vuex 中的 state 会重新变为初始状态。(解决方案:插件 vuex-persistedstate)
什么时候适合用 VueX?
如果不打算开发大型单页应用,使用 vuex 可能是繁琐冗余的。如果项目比较小比较简单,使用 prop 和 $emit 完成父子间的传参,或者使用 $eventBus 实现复杂的组件间的通信也是可以满足需求的。vuex 具体应用在哪取决于项目的规模以及具体的业务场景,可能是为了解决多层嵌套组件之间的通信问题,或是为了更好地管理应用中错综复杂的状态关系,而不能为了用 vuex 而在项目中使用 vuex。
vuex 的应用场景?
VueX 刷新页面后数据丢失如何解决?
Vue Router 是什么?
vue-router 路由是 vue 的一个插件库,用于构建单页面应用。路由模块的本质就是建立起 url 路径和页面之间的映射关系,在 vue-router 的单页面应用中,页面的路径的改变就是组件的切换。路由主要负责将浏览器请求映射到特定的组件代码中,也就是通过解析 URL 来实现页面切换和跳转。
什么是路由懒加载?
路由懒加载也叫延迟加载,既在需要的时候加载,随用随载。也就是不用一开始就去加载所有页面,只加载当前页面。当切换页面的时候,再加载对应的路由。避免不必要的资源加载,提高应用程序的加载速度。
为什么要路由懒加载?
如果没有应用懒加载,运用 webpack 打包后的文件将会异常的大,影响页面加载。像进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,即使做了 loading 也是不利于用户体验。使用懒加载当路由被访问的时候才加载对应组件,可以减少页面加载用时,提高页面加载速度,提升用户体验。
如何实现路由懒加载?
- {
- path: '/home',
- name: '/Home',
- component:resolve=>require(['@/pages/Home'],resolve),
- meta: {
- show: true
- }
- }
- {
- path: '/home',
- name: 'Home',
- component:()=>import(/* webpackChunName:"chunkName" */ '@/pages/Home'),
- meta: {
- show: true
- }
- }
- {
- path: '/home',
- name: 'Home',
- component:r=>require.ensure([],()=>r(require('@/pages/Home')),'chunkName'),
- meta: {
- show: true
- }
- }
- // 注:r 就是 resolve。
区别:
什么是动态路由?
顾名思义,路由是动态的不是写死的。我们可以根据自己不同的需求加载不同的路由,渲染不同的页面组件。动态路由的使用一般结合角色权限控制一起使用,例如后台管理系统可以根据动态路由实现不同角色权限显示不同菜单。
如何实现动态路由?
Vue 实现动态路由通常有两种方式:
思路:使用全局前置守卫,在页面加载前将当前用户所用到的路由列表通过 addRoutes 方法注入到 Router 实例中。
具体实现(第1种):
具体实现(第2种):
如何实现带参数的动态路由匹配?
有的时候,一个 user 组件,它应该对所有用户进行渲染,但是用户 ID 不同。可以在路径中使用一个动态字段来实现,我们称之为 路径参数 :,通过在路径后添加一个冒号以及一个动态字段实现动态路由。
- {
- path: '/home/users/:pid',
- name: 'users',
- component:()=>import('../views/users')
- }
$route 和 $router 的区别?
如何实现 Vue 路由跳转?
1. router-link:声明式导航,在页面中调用,通过:to跳转,通常在不需要逻辑跳转时使用。
2. this.$router.push:编程式导航,在函数里面调用,通常在需要逻辑跳转时使用。
3. this.$ router.replace:类似于 push,但 history 栈中添加记录。
4. this.$router.resolve:打开新窗口跳转。
5. this.$router.go(n):相当于当前页面向前或向后跳转多少个页面。
路由跳转方式和参数传递方式
params 传参和 query 传参的区别:
path 跳转和 name 跳转的区别:
vue 路由钩子函数 (导航守卫)
HashRouter 和 HistoryRouter 的区别?
实现原理:
区别:
什么是 Vue 组件?
组件是 Vue 强大的功能之一,Vue 鼓励使用组件化开发,将页面拆分成多个独立的组件,每个组件负责特定的功能,我们可以在每个组件内封装自定义内容与逻辑,组件可以复用、嵌套和组合,提高代码的可维护性和复用性。
组件开发的好处?
提高开发效率、提高复用性、使代码逻辑更加清晰,方便项目的后期维护、便于协同开发
什么情况下需要封装组件?
组件封装流程?怎么封装组件的?
使用 Vue.extend 方法创建一个组件,然后使用 Vue.component 方法注册组件。但是我们一般用脚手架开发项目,每个 .vue 单文件就是一个组件。在另一组件 import 导入,并在 components 中注册。首先建立好自定义模板,准备好组件的数据的输入,子组件定好 props 里面的数据和类型,接收父组件传过来的数据,然后通过 $emit( )暴露输出子组件的数据返回给父组件。
传统流程:
views 放页面级的组件、commen 放公共组件、feature 放功能组件
vue 的组件通信有哪些方法?
父子传参:
边界访问 (父子通信):
兄弟通信:
跨级通信:
事件总线 $eventBus:
- // main.js
- import Vue from 'vue'
- // 创建事件总线,就相当于创建了一个新的 vue 实例
- const bus = new Vue()
- // 把 bus 挂载到了 Vue 的原型上, 保证所有的组件都能通过 this.$bus 访问到事件总线
- Vue.prototype.$bus = bus
页面使用:发布事件-传递值
this.$bus.$emit('send', 'hello') //(事件名,参数)
订阅事件,接收组件值
- // 在 created 中订阅,('事件名', 事件回调函数)
- this.$bus.$on('send', msg => {
- console.log(msg)
- })
注意:在子组件销毁后记得进行取消订阅事件,否则会导致多余调用事件监听,造成资源浪费,导致数据错乱。通常在 beforeDestroy 子组件销毁前调用 this.$bus.$off 移除。
为什么组件的 data 必须是一个函数?
keep-alive 是什么?
keep-alive 是 vue 内置的一个组件,是一个抽象组件,它自身不会渲染一个 DOM 元素,也不会出现在父组件链中,使用 keep-alive 包裹动态组件时,会缓存不活动的组件实例,保留组件状态,避免重新渲染,缓存组件能加快速度,降低消耗资源。(组件进行切换的时候,默认会进行销毁,消耗资源)
具体实现
当组件在 <keep-alive> 内被切换的时候,activated (激活) 和 deactivated (取消激活) 这两个生命周期钩子函数将会被对应执行。页面第一次进入的时候,钩子触发的顺序是 created->mounted->activated。页面退出的时候会触发 deactivated,当再次前进或者后退的时候只触发 activated。当 keep-alive 组件激活时,触发 activated。keep-alive 组件停用时调用 deactivated。
Vue 优点:
Vue 缺点:
React 优点:
React 缺点:
Anguar 优点:
Anguar 缺点:
Angular 框架过重,不像 Vue 和 React 是非常轻量级的框架,过大的框架导致性能方面消耗严重。适用在大型的浏览器端,大型网站项目。
angular 入门很容易但深入后概念很多,学习中较难理解,学习成本相对来说较高。
文档例子非常少,官方的文档基本只写了 api,一个例子都没有,很多时候具体怎么用都是google 来的,或直接问 misko,angular 的作者。
指令的应用的最佳实践教程少,angular 其实很灵活,如果不看一些作者的使用原则,很容易写出四不像的代码。
什么是 服务端渲染 SSR?
服务端渲染的优势?
服务端渲染的缺点?
详细步骤: uni-app ISO 打包详细步骤
详细步骤: uniapp 小程序打包详细步骤
api:uni.uploadFile。
格式:上传的地址 url,上传类型 fileType,图片路径 filePath,文件对应的key name,成功的回调
- uni.uploadFile({
- url: '要上传的地址',
- fileType:'image',
- filePath:'图片路径',
- name:'文件对应的key',
- success: function(res){
- console.log(res)
- }
- })
uni.getLocation
使用 onPageScroll 监听
给 image 标签添加 mode=‘widthFix’
优点:
缺点:
jQuery:
vue:
微信小程序:
uni-app:
JQ传参:通过url拼接参数进行传参。
VUE传参:
uni-app,小程序传参 :通过跳转路径后面拼接参数来进行跳转传参。
vue 和 uni-app 动态绑定一个变量的值为元素的某个属性的时候,会在属性前面加上冒号 ":"。小程序绑定某个变量的值为元素属性时,会用两个大括号 {{}} 括起来,如果不加括号,为被认为是字符串。
全局数据、Storage存储、eventBus。
例如:http://www.baidu.com/index.html?name=mo&age=25#dowell
这个URL 包括:协议部分、域名、端口、路径(虚拟路径)、携带的参数、哈希值。
共同点:都是存储在浏览器本地的、相对不安全。
不同点:
请求行
请求头
请求体
响应行
响应头
响应体
get 提交的数据最大是2k,post 理论上没有限制。其中,get 发送的数据在原则上 url 长度无限制,实际上取决于浏览器,浏览器会限制 url 的长度。
get 在浏览器回退时不产生影响,post 会再次提交请求。(get请求中的回退操作实际上浏览器会从之前的缓存中拿结果)
get 请求参数会被完整保留在浏览器历史记录里,而 post 中的参数不会被保留。
get 请求只能进行 url 编码,post 支持多种编码方式。
get 比 post 更不安全,因为参数直接暴露在 url 上,所以不能用来传递敏感信息。
get 产生一个 TCP 数据包,浏览器会把 http header 和 data 一并发送出去,服务器响应200(返回数据)。post 产生两个 TCP 数据包,浏览器先发送 header,服务器响应100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。【在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的 TCP 在验证数据包完整性上,有非常大的优点。并不是所有浏览器都会在 POST 中发送两次包,Firefox就只发送一次】
1开头(收到请求,正在处理)
2开头(请求成功)
200 (成功) 201 (已创建) 202 (已接受) 203 (非授权信息)
204 (无内容) 205 (重置内容) 206 (部分内容)
3开头 (请求被重定向)
300 (多种选择) 301 (永久移动) 302 (临时重定向) 303 (查看其他位置)
304 (未修改) 305 (使用代理) 307 (临时重定向)
4开头 (请求错误)
400(错误请求) 401(未授权) 403(禁止) 404(未找到) 405(方法禁用)
406(不接受) 407(需要代理授权) 408(请求超时) 409(冲突) 410(已删除)
411(需要有效长度) 412(未满足前提条件) 413 (请求实体过大)
414(请求的 URI 过长) 415 (不支持的媒体类型) 416 (请求范围不符合要求)
417(未满足期望值)
5开头(服务器错误)
500 (服务器内部错误) 501 (尚未实施) 502 (错误网关)
503 (服务不可用) 504 (网关超时) 505 (HTTP 版本不受支持)
token 一般是用来判断用户是否登录的,它内部包含的信息有 uid(用户唯一的身份标识)、time(当前时间戳)、sign(签名)。token 可以存放在 Cookie 中,token 是否过期,应该由后端来判断,不该前端来判断,所以 token 存储在 cookie 中只要不设置 cookie 的过期时间就可以了,如果 token 失效,就让后端在接口中返回固定的状态表示 token 失效,需要重新登录,再重新登录的时候,重新设置 cookie 中的 token 就行。
options 请求就是预检请求。当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 options 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
什么是浏览器内核?
浏览器最核心部分, Rendering Engine 渲染引擎,一般叫浏览器内核。负责对网页语法的解释并渲染网页,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。
有什么用?
浏览器内核对于浏览器而言,是基础,是依托,决定了网页的呈现的内容、格式以及效果。
有哪一些?
因为不同浏览器的浏览器内核不一样,所以对同一段代码有不同的解析,造成页面显示效果不统一的情况。在大多数情况下,我们的需求是,无论用户用什么浏览器来查看我们的网站或者登陆我们的系统,都应该是统一的显示效果。
前端性能优化分为两类,一类是文件加载更快,另一类是文件渲染更快。
加载更快的方法:
渲染更快的方法:
好处:
怎么优化?
页面级别的优化:HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等
代码级别的优化:js 中的 DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等。
页面级优化:
应用场景:axios 为开发者提供了这样一个 API:拦截器。拦截器分为请求拦截器和响应拦截器。请求拦截器:在接口请求之前做的处理,比如为每个请求带上相应的参数,像 token、时间戳等。 返回拦截器:在接口返回之后做的处理,像对返回的状态进行判断,例如判断 token 是否过期。
- XHR.onreadystatechange = function(){
- if(XHR.readyState == 4 && XHR.status == 200){
- console.log(XHR.responseText);
- }
- }
fetch 是一种 HTTP 数据请求的方式,是 XMLHttpRequest 的一种替代方案。Fetch 函数就是原生js,没有使用 XMLHttpRequest 对象。fetch() 方法返回一个 Promise 解析 Response 来自 Request显 示状态(成功与否)的方法。
浏览器拿到 HTML,先将 HTML 转换成 dom 树,再将 CSS 样式转换成 stylesheet,根据 dom 树和 stylesheet 创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。
git 在开发中用来进行项目托管,项目中一般有三个分支,主分支master 只有项目负责人有操作权限,平时开发功能是在 develop 开发分支下创建的子分支也就是 feature 功能分支下开发的,功能开发完测试没问题了,切换到 develop 分支并拉取最新的 develop 分支,然后合并自己的任务分支并推送 develop 分支,再由项目负责人合并到 master 分支上。
所谓冲突指的就是,两个开发者对同一个文件同一个位置做出了不同的内容修改,然后在进行分支合并时或者是从远程仓库拉取代码到本地库时,就会产出冲突报错;两个不同的版本,导致 git 不知道要接受那个。
寻找冲突:首先要找到出现冲突的位置,通过 git merge 分支名 如果有冲突的话会提示那些文件有冲突。
修改冲突:找到冲突文件对比差异,然后手动修改为正确的。如果使用命令的话,使用 cat 冲突文件 查看不同分支代码的差异,然后 vim 进入冲突文件进行删除修改正确代码。
提交修改后的冲突文件:分别执行命令 git add 添加到暂存区、git commit -m 提交到本地库、最后 git push 推送到远程库就可以了。
原理:比如购物车商品数量,在商品列表页面添加商品会更改这个值,在详情页增减商品数量会更改这个值,进入购物车删除商品也会更改这个值,通过提交 mutation 来更改这个值就很简单明了。当然也可以每次都调用获取购物车数量的接口,也可以实现,但每一次的 HTTP 请求都是对浏览器性能的消耗。
具体实现:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。