前端整理 —— vue 1

1. vue 的生命周期

经典爱问,感觉内容挺多的

  1. 介绍一下有哪几个
    vue2中的生命周期有11个,分别为beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,activated,deactivated,errorCaptured,而vue3中采用组合式api,将各个生命周期前面加上on作为api,但没有onBeforeCreate和onCreated,多出来了setup,并且将beforeDestroy和destroyed分别改名为onBeforeUnmount和onUnmounted
  2. 一般在哪个生命周期进行数据请求
    created和mounted都可以,基本上是created,因为vue是数据驱动的,也就是说只要能操作到data中的数据时即可请求(要把数据挂载到data上),如果请求需要获取,借助,依赖,改变dom,这时请求放在mounted
    (beforeRouter也行,但是没必要,不如created早,还获取不到dom)
  3. activated 和 deactivated
    1. 设置了 keep-alive 缓存的组件,会多出这两个生命周期钩子
    2. 首次进入组件时:beforeRouteEnter > beforeCreate > created> mounted > activated > … … > beforeRouteLeave > deactivated
    3. 再次进入组件时:beforeRouteEnter >activated > … … > beforeRouteLeave > deactivated

2. v-if 和 v-show 区别

  1. v-if 是惰性的,只有当第一次为 true 的时候,才会渲染元素
  2. v-if 相当于把元素从 dom 树中删除,而 v-show 相当于把 display 设为 none,所以频繁的修改元素是否显示,一般用 v-show

3. v-if 和 v-for 能否一起使用

vue2 中 v-for 的优先级高于 v-if,vue3 中 v-if 的优先级高于 v-for

4. vue3 相对于 vue2 性能有哪些方面提升

  1. 编译阶段
    1. diff算法优化
      vue3在diff算法中相比vue2增加了静态标记(在对应VNode对象上),类似于<p>1<p>这种,会被标上静态标记,而类似于<p>{ {data}}<p>这种不会被标上静态标记,在diff比较的时候,如果发现被标上了静态标记,就不会再进行比较
    2. 静态提升
      vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用,即不是每次render的时候都createVNode一次,而是把createVNode给用const常量保存下来,下次render渲染的时候,直接把这个VNode传进去就行了
    3. 事件监听缓存
    4. SSR优化
  2. 源码体积
    相比Vue2,Vue3整体体积变小了,除了移出一些不常用的API,再重要的是Tree shanking,任何一个函数,如ref、reavtived、computed等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小
  3. 响应式系统
    vue2中采用 defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式,而vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历

5. v-model 的原理

v-model 用在 input 上

绑定在 input 上时,v-model 其实就是 v-bind 绑定 value 和 v-on 监听 input 事件的结合体

  1. v-bind 绑定一个 value 属性
  2. v-on 指令给当前元素绑定 input 事件

模拟实现:

// 1. 通过 v-bind:value 绑定 username 变量,每次输入内容的时候触发input事件
// 2. 通过事件对象参数 event.target.value 获得输入的内容,并且把这个内容赋值给username
// 3. 此时更改username时input输入框会变化,更改input输入框时username变量会变,从而实现了v-model的双向绑定功能
<input v-model="username" />
<input type="text" :value="username" @input="username = $event.target.value" />

v-model 用在组件上

实现场景:父组件 price 的初始值是 100,子组件是一个输入框;输入框的值改变时,能实时更新父组件的 price

// 父组件
<currency-input v-model="price"></currentcy-input>
// 相当于 <currency-input :value="price" @input="price = $event.target.value"></currency-input>
// 所以相当于向子组件传了一个 value 值,和绑定了一个 input 事件

// 子组件
<template>
  	<input
    	:value="value"
   		@input="$emit('input', $event.target.value)" 
  />
</template>

<script>
export default {
  	props: {
    	value: String,  // 父组件传过来的 value 值
  	}
}
</script>

子组件好看一点的写法

// 子组件(好看点的写法)
<template>
  <button @click="add">点击按钮自增 1</button>
</template>

<script>
export default {
  props: {
    value: Number, // 属性名必须是 value
  },

  methods: {
    add() {
      this.$emit('input', this.value + 1) // 事件名必须是 input
    },
  }
}
</script>

v-model 应用到组件上,会有一些体验不好的场景,因为它默认会把 value 作为组件的属性,把 input 作为给组件绑定事件时的事件名

但在 Vue 2.2 及以上版本,你可以在定义组件时通过 model 选项的方式来定制 prop / event:

// 父组件
<my-button v-model="number"></my-button>

// 子组件
<template>
  	<button @click="add">点击按钮自增 1</button>
</template>

<script>
export default {
  	model: {
    	prop: 'num', // 自定义属性名
    	event: 'addNum' // 自定义事件名
 	},
  	props: {
    	num: Number,
  	},
  	methods: {
    	add() {
      		this.$emit('addNum', this.num + 1)
    	},
  	}
}
</script>

6. hash 和 history 模式

  • hash 模式

    • 原理:
      hash 就是指 url 中 # 号后面的字符,由于 hash 值的变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发onhashchange 事件(onhashchange 是 window 对象的属性),假如在 onhashChange 事件中获取当前的 hash 值,并根据 hash 值来修改页面内容,则达到了前端路由的目的

    • 特点:
      hash 虽然出现 url 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。hash 本来拿来做页面定位的,如果拿来做路由的话,原来锚点功能就不能用了。hash 模式又叫做前端路由,因为改变 hash 值不会向后端发送请求

    • hash 原本功能(锚点功能):

      • hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变 # 后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说 # 是用来指导浏览器动作的,对服务器端完全无用,HTTP 请求中也不会不包括 #
      • 同时每一次改变 # 后的部分,都会在浏览器的访问历史中增加一个记录,使用 ”后退” 按钮,就可以回到上一个位置
      <style>  
          div {  
              height: 800px;  
              width: 400px;  
              border: 2px solid black;  
          }  
          h2 {  
              position: fixed;  
              margin:50px 500px;  
          }  
      </style>  
      
      <h2>  
          <a href="#div1">to div1</a>  
          <a href="#div2">to div2</a>  
          <a href="#div3">to div3</a>  
      </h2>  
      <div id="div1">div1</div>  
      <div id="div2">div2</div>  
      <div id="div3">div3</div>  
      
  • history 模式

    • 前提:
      • 在 HTML5 之前,浏览器就有 history 对象了,只能用于多页面之间的跳转,有 go(),forward(),back() 方法,在 HTML5 规范中,history 中增加了新的 API,pushState() 和 replaceState()
        history.go(n) // n>0前进n页;n<0后退n页
        history.forward() // 前进一页
        history.back() // 后退一页
        
        /*
          参数说明:
            state:合法的JavaScript对象,可以用在popstate对象中
            title:标题,基本忽略,用null
            url: 任意有效的url,将要跳转的新地址
        */
        history.pushState(state, title, url) // 保留现有记录的同时,将url加到历史记录中
        history.replaceState(state, title, url) // 将历史记录中的当前页面替换成url
        
        // 但replaceState()是修改当前历史记录,而pushState()是创建新的历史记录
        // 实例1,如果当前网页是:www.com
        
        history.pushState(null,null,'/html.1'); // www.com/html.1
        history.pushState(null,null,'/html.2'); // www.com/html.2
        history.replaceState(null,null,'html.3'); // www.com/html.3   replaceState会替换刚刚那个pathname
        
        history.back();  // 后退一次,www.com/html.1
        history.back();  // 后退一次,www.com
        history.go(2)   // 前进两次,www.com/html.3
        
      • 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。pushState() 方法可以改变 URL 地址且不会发送请求,replaceState() 方法可以读取历史记录栈,还可以对浏览器记录进行修改。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求
    • 原理:
      • history 模式原理可以这样理解,首先我们要改造我们的超链接,给每个超链接增加 onclick 方法,阻止默认的超链接跳转,改用 history.pushState 或 history.replaceState 来更改浏览器中的 url,并修改页面内容。由于通过 history 的 api 调整,并不会向后端发起请求,所以也就达到了前端路由的目的
      • 在浏览器某些行为,比如点击后退、前进按钮(或者在 js 中调用 history.back(),history.forward(),history.go() 方法),则会触发 window.onpopstate 事件,监听页面根据路由地址修改页面内容,但调用 history.pushState() 或 history.replaceState() 不会触发 popstate 事件,所以如果用户使用浏览器的前进后退按钮,也能对应更改页面内容
    • 特点:
      • history 模式的 url 发生变化时不会立即向服务器发起请求,刷新会立即请求
      • 浏览器在刷新的时候,会按照路径发送真实的资源请求,如果这个路径是前端通过 history API 设置的 URL,那么在服务端往往不存在这个资源,于是就返回 404 了。因此在线上部署基于 history API 的单页面应用的时候,一定要后端配合支持才行,否则会出现大量的 404
  • hash 和 history 区别

    • 外观:hash 的 url 有个 # 符号,history 没有,所以 history 外观更好看
    • 刷新:hash 刷新会加载到地址栏对应的页面,history 刷新浏览器会重新发起请求,如果服务端没有匹配当前的 url,就会出现 404 页面。
    • 兼容性:hash 能兼容到 IE8,history 只能兼容到 IE10
    • 服务端支持:hash(#及后面的内容)的变化不会导致浏览器向服务器发起请求;history刷新会重新向服务器发起请求,需要在服务端做处理,例如果没有匹配到资源,就返回同一个 html 页面
    • 原理:hash 通过监听浏览器的 onhashchange() 事件,查找对应的路由规则。而 history 利用 H5 新增的 pushState() 和 replaceState() 方法改变 url
    • 记录:hash 模式只有 # 后面的内容被修改才会添加新的记录栈。而 history 通过 pushState() 设置的 url 于当前 url 一模一样也会被记录到历史记录栈

7. watch 和 computed 的区别

  • 功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
  • 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
  • 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
  • computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
  • 使用场景:computed ---- 当一个属性受多个属性影响的时候,使用computed-----购物车商品结算。watch–当一条数据影响多条数据的时候,使用 watch -----搜索框

8. defineProperty 与 proxy 的优缺点

defineProperty 的优缺点

  • 优点:
    • 兼容性好
    • 性能好
  • 缺点:
    • 无法检测到对象属性的新增或删除 和 数组内部的变化
      ( vue 为了监听数组变化重写了 push,pop,unshift,shift,splice,sort,reverse )
Proxy 的优缺点
  • 优点
    • Proxy 可以监听嵌套,这样就不需要知道提前知道要拦截的所有属性,而 Object.defineProperty() 的 getter/setter 就不能嵌套
  • 缺点
    • 兼容性差
      1. Babel 可以将较新版本的 JavaScript 代码转换成老旧浏览器能够运行的代码
      2. 在处理 Proxy 兼容性问题时,Babel 会检测当前环境是否支持原生的 Proxy 对象。如果当前环境不支持原生的 Proxy 对象,Babel 就会通过内置的 polyfill(垫片)来模拟实现 Proxy 对象的功能,以解决兼容性问题
      3. 这个 polyfill 可以在 Babel 的 @babel/plugin-proposal-proxy-instrumentation 插件中使用。该插件会将代码中的 Proxy 相关语法转换为对 polyfill 中的函数的调用,从而实现对 Proxy 对象的模拟实现
      4. 需要注意的是,虽然 polyfill 可以提供与原生 Proxy 对象相似的功能,但由于其实现方式不同,因此在某些情况下可能会导致性能或行为差异等问题
    • 性能差
      • 虽然 proxy 有性能问题,但同样性能很差的 Promise 在最近几年中也被快速采用,并且 proxy 作为新标准将受到浏览器厂商重点持续的性能优化

猜你喜欢

转载自blog.csdn.net/m0_52212261/article/details/127792394