vue笔记不断更新中

官网

1、MVVM理解:

Model View ViewModel 的缩写.
Model  数据模型  也可以在Model中定义数据修改和操作的业务逻辑
View     视图层  UI组件,将数据模型转化为UI视图
ViewModel  监听模型数据的改变和控制视图行为、处理用户交互,
    简单理解就是一个同步View 和 Model的对象,连接Model和View。

    在MVVM架构下,View 和 Model 之间并没有直接的联系,
而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 
因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
    ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,
而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,
因此开发者只需关注业务逻辑,不需要手动操作DOM, 
不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

2、双向数据绑定的实现

2.0实现原理如下

Vue实现数据双向绑定的原理:Object.defineProperty()
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。
当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。
用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,
通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;
视图交互变化(input)—>数据model变更双向绑定效果。

缺点是:
1.需要对原始数据进行克隆 不然死循环
2.如果我们想给对象中的数据进行get和set的拦截 就要一个个设置
 对象中的属性都要单独的监听一下 如果有多个就要循环遍历了 分别来监听了

3.0实现原理如下(Proxy实现数据劫持)

observe(data) {
  const that = this;
  let handler = {
   get(target, property) {
      return target[property];
    },
    set(target, key, value) {
      let res = Reflect.set(target, key, value);
      that.subscribe[key].map(item => {
        item.update();
      });
      return res;
    }
  }
  this.$data = new Proxy(data, handler);
}

proxy参考

3、Vue生命周期:

(1)beforeCreate vue实例创建之前,在数据观测和初始化事件还未开始
(2)created      vue实例创建完成, 完成数据观测,属性和方法的运算,初始化事件
    官方解释:在实例创建完成后被立即调用。
                在这一步,实例已完成以下的配置:
                数据观测 (data observer),property 和方法的运算,watch/event 事件回调。
                然而,挂载阶段还没开始,$el property 目前尚不可用。

vue3创建的这个过程再setup中完成所以上面这俩生命周期notneed

(3)beforeMount  el属性还没有显示出来beforeMount(载入前)在挂载开始之前被调用,
    相关的render函数首次被调用,实例已完成以下的配置:编译模板,
    把data里面的数据和模板生成html。 
    注意此时还没有挂载html到页面上。
    (该钩子在服务器端渲染期间不被调用。)
(4)mounted      在el被新创建的vm.
(5)beforeUpdate 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。
    可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
    (该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。)
(6)updated      在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。
                调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。
                然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。
                该钩子在服务器端渲染期间不被调用。
                注意 updated 不会保证所有的子组件也都一起被重绘。
                如果你希望等到整个视图都重绘完毕,可以在 updated 里使用 vm.$nextTick
(7)activated    被 keep-alive 缓存的组件激活时调用。
    该钩子在服务器端渲染期间不被调用。
(8)deactivated  被 keep-alive 缓存的组件停用时调用。
    该钩子在服务器端渲染期间不被调用。
(9)beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。
    该钩子在服务器端渲染期间不被调用。
(10)destroyed   实例销毁后调用。
                该钩子被调用后,对应 Vue 实例的所有指令都被解绑,
                所有的事件监听器被移除,所有的子实例也都被销毁。
    该钩子在服务器端渲染期间不被调用。

(11)errorCaptured
2.5.0+ 新增
● 类型:(err: Error, vm: Component, info: string) => ?boolean
● 详细:
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
你可以在此钩子中修改组件的状态。因此在捕获错误时,在模板或渲染函数中有一个条件判断来绕过其它内容就很重要;不然该组件可能会进入一个无限的渲染循环。
错误传播规则
○ 默认情况下,如果全局的 config.errorHandler 被定义,所有的错误仍会发送它,因此这些错误仍然会向单一的分析服务的地方进行汇报。
○ 如果一个组件的继承或父级从属链路中存在多个 errorCaptured 钩子,则它们将会被相同的错误逐个唤起。
○ 如果此 errorCaptured 钩子自身抛出了一个错误,则这个新错误和原本被捕获的错误都会发送给全局的 config.errorHandler。
○ 一个 errorCaptured 钩子能够返回 false 以阻止错误继续向上传播。本质上是说“这个错误已经被搞定了且应该被忽略”。它会阻止其它任何会被这个错误唤起的 errorCaptured 钩子和全局的 config.errorHandler。

1.什么是vue生命周期?
答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
2.vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
3.vue生命周期总共有几个阶段?
答:通常情况下分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
如果使用了keepAlive那么这些组件还有组件被激活/停用两个阶段
2.5.0之后,如果有子孙组件,那么在子孙组件错误时会有一个errorCaptured
4.第一次页面加载会触发哪几个钩子?
答:会触发 beforeCreate, created, beforeMount, mounted 。
5.DOM 渲染在 哪个周期中就已经完成?
答:DOM 渲染在 mounted 中就已经完成了。

vue生命周期

4、组件传参

父组件与子组件传值
父传子

props方法接收数据,父组件中指定$children

子传父
$emit:

父组件代码:

<child ref='child' @childFun='childFun'></child>
childFun(params){
	console.log('子组件传给父组件的值:'params)
}

子组件代码:

fun(){
 this.$emit('childFun',"It's params")
 }
$parent

这个属性只在子组件中调用即可

1、对父组件data中智重新赋值
this.$parent.data.xxx=xxx
2、在子组件中使用父组件某个计算属性
this.xxx=this.$parent.computedData
3、在子组件中调用父组件方法
this.$parent.fun()

兄弟组件传值

bus 创建一个空的vue实例,通过向这个空的vue实例传入传出

上层组件与下层组件传参(中间隔代)

上层组件->下层组件,除了上面的父传子的方法,还可以通过provide/inject(提示:provide 和 inject
绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

vue官方对于provide与inject解释

5、v-route原理

Vue-router是Vue.js官方的路由管理器,它实现了前端路由,使得UI与URL之间的映射关系可被单向改变,即URL变化能触发UI的更新,而无需刷新页面。在Web前端单页应用SPA(Single Page Application)中,这种技术尤为重要。

解释/定义

Vue中的v-route是用于实现前端路由的功能,它通过改变URL来展示不同的页面内容。

v-route的实现原理如下:

  1. 定义路由规则:在Vue项目中,需要定义一组路由规则,每个规则对应一个路径和对应的组件。路由规则可以通过Vue Router插件进行配置。
  2. 解析URL:当用户访问某个URL时,Vue会根据定义的路由规则解析出对应的路径和组件。不同路由模式,解析也不同,history模式下,利用HTML5 History API ↗来解析URL并创建真实的URL(可以实现友好的URL和SEO);hash模式下,它会利用URL的hash(#)来进行路由管理
  3. 创建组件实例:Vue会使用Vue Component构造函数创建对应的组件实例。
  4. 挂载组件到DOM:Vue将创建的组件实例挂载到指定的DOM元素上,完成页面内容的更新。
  5. 监听URL变化:Vue会监听浏览器的URL变化事件,当URL发生变化时,重新解析并更新页面内容。

需要注意的是,v-route只是Vue中的一个指令,它并不包含具体的路由实现逻辑。实际的路由功能是通过Vue Router插件来实现的。Vue Router是一个独立的插件,提供了完整的路由功能,包括路由配置、导航守卫、懒加载等特性。

6、v-bind

解释:

v-bind是Vue.js中的一个指令,主要用于属性绑定,包括class属性、style属性、value属性、href属性等。v-bind可以将元素的属性与数据进行绑定,当数据发生变化时,元素的属性也会自动更新。

使用:

在具体实现上,v-bind的参数会被编译为属性名,表达式内有data数据,会产生动态连带效果。
例如,<div v-bind:id="someObject"></div>中,id是一个属性名,someObject是一个变量,这个变量的值会被用来设置div元素的id属性。
值得注意的是,虽然参数可以随便写,但是始终需要写属性名,否则将没有意义。

同时,v-bind还与插值语法如插值表达式、v-text等密切关联,通过使用这些语法可以为元素绑定数据。例如,可以通过v-bind:属性名='合法JS表达式'的形式为元素的属性绑定数据。
此外,v-bind还被广泛应用于从服务器动态获取样式后动态绑定类名,以实现后端对前端的控制。

实现原理
通过解析模板字符串,将v-bind指令替换为对应的JavaScript代码,从而实现动态绑定。

以下是一个简单的示例,展示了如何在Vue中使用v-bind指令:

<template>
  <div id="app">
    <h1 v-bind:title="message">{{ message }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  }
};
</script>

在这个示例中,我们使用v-bind:title来动态地绑定title属性到message变量。当message的值发生变化时,title属性也会相应地更新。

要实现v-bind指令的解析和替换,Vue会遍历模板字符串,找到所有的v-bind指令,并将其替换为对应的JavaScript代码。具体来说,它会生成以下代码:

this._update(this._dirs, this._data);

其中,this._dirs是一个包含所有v-bind指令的对象,this._data是一个包含所有数据属性的对象。this._update方法会根据这些信息,动态地更新DOM元素的属性。

7、filters

过滤器
(1)、全局定义:

import * as filter from "./filter.ts";
const importFilter = Vue => {
  Vue.filter('thousands', filter.thousands)
}
export default importFilter

filter.ts中内容如下:

//全局过滤价格显示千分位间隔符
export function thousands(value){
  if (!value){
    value =''
  } else {
    var result = '', counter = 0 ,one='' ,two=''
    value = (value || 0).toString();
    if (value.includes('.')){
      one = value.split('.')[0],
        two = value.split('.')[1]
      for (var i = one.length - 1; i >= 0; i--) {
        counter++;
        result = one.charAt(i) + result;
        if (!(counter % 3) && i != 0) {
          result = ',' + result;
        }
      }
      return result+'.'+ two;
    } else {
      for (var i = value.length - 1; i >= 0; i--) {
        counter++;
        result = value.charAt(i) + result;
        if (!(counter % 3) && i != 0) {
          result = ',' + result;
        }
      }
      return result;
    }
  }
}

main.ts中注册

import Vue from 'vue'
import importFilter from "@/filters/index.js";
/**
 *注册过滤器
 * */
importFilter(Vue)

(2)、页面定义

  filters: {
    thousands(value) {
      if (!value) {
        value = ''
      } else {
        var result = '', counter = 0, one = '', two = ''
        value = (value || 0).toString();
        if (value.includes('.')) {
          one = value.split('.')[0],
            two = value.split('.')[1]
          for (var i = one.length - 1; i >= 0; i--) {
            counter++;
            result = one.charAt(i) + result;
            if (!(counter % 3) && i != 0) {
              result = ',' + result;
            }
          }
          return result + '.' + two;
        } else {
          for (var i = value.length - 1; i >= 0; i--) {
            counter++;
            result = value.charAt(i) + result;
            if (!(counter % 3) && i != 0) {
              result = ',' + result;
            }
          }
          return result;
        }
      }
    }
   }

使用:

<div>{{sum | thousands}}</div>
<!--多个过滤器同时使用 依次往后 用 | 管道运算符隔开就好 -->
<div>{{sum | thousands | filter2}}</div>

8、directives

(1)、全局定义:

import { on } from '@/libs/tools'
const directives = {
  blur: {
    inserted: (el, binding, vnode) => {},
    update: (el, binding, vnode) => {}
  }
}

export default directives

main.ts中注册

import Vue from 'vue'
import importDirective from '@/directive';
/**
 * 注册指令
 */
importDirective(Vue)

(2)、页面定义

  directives: {
    blur: {
      inserted: function(el, binding, vNode) {
        setInterval(function() {
          let a = vNode.context;
          if (binding.value) {
            for (let i = 0, len = a.tableData.length; i < len; i++) {
              let el2 = document.getElementById(`input${i}`).children;
              if (el2[1].nodeName == "INPUT") {
                el2[1].blur();
              }
            }
          } else {
            el.focus();
          }
        }, 1000);
      }
    }
  },

使用:

<Input v-blur v-model='num'/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伊昂呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值