• Vue基础理论篇


    1、MVC、MVP、MVVM模式的概念与区别
    1】MVC

    a、概念
    Model(模型):表示应用程序核心(如数据库)
    View(视图):显示UI效果(HTML页面)
    Controller(控制器):处理输入(业务逻辑)
    b、过程(单向)
    View 传送指令到 Controller
    Controller 完成业务逻辑后,要求 Model 改变状态
    Model 将新的数据发送到 View,View得到更新
    c、优缺点
    优点:M和V之间是完全隔离的, 所以在业务场景切换时, 通常只需要替换相应的C, 复用已有的M和V便可快速搭建新的业务场景. MVC因其复用性, 大大提高了开发效率, 现已被广泛应用在各端开发中
    缺点: 视图V与控制器C间的过于紧密的连接,没有区分业务逻辑和业务展示,
    1 这对单元测试很不友好,
    2 视图jsp模板引擎,这些还会让前端人员和后端人员的一些职责重复

    2】MVP
    a、概念
    MVP是针对MVC的缺点而进行了改进
    模型(Model):数据库相关的操作、文件的访问和数据结构等
    视图(View):专注于显示,如Web前端(HTML/CSS/JavaScript)
    展示器(Presenter):连接模型和视图,处理视图的请求并根据模型更新视图(中介)

    b、优缺点
    优点:
    (mvc是m驱动v的变更,mvp是p展示器驱动v的变更)
    MVP用展示器代替了控制器,而展示器是可以直接更新视图,所以MVP中展示器可以处理视图的请求并递送到模型又可以根据模型的变化更新视图,实现了视图和模型的完全分离,有点类似双向绑定
    缺点:
    视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更

    3】MVVM

    a、概念
    MVVM是MVP更进一步的发展,把软件系统分为三个基本部分:模型(Model)、视图(View)和视图模型(ViewModel)
    模型(Model):数据库相关的操作、文件的访问和数据结构等。
    视图(View):专注于显示,如Web前端(HTML/CSS/JavaScript)
    视图模型(ViewModel):监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
    b、优缺点
    优点:通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 VM 来统一管理。
    1】低耦合:视图(View)可以独立于 Model 变化和修改,一个 ViewModel 可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变(React单向绑定)。
    2】可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多 view 重用这段视图逻辑。
    3】独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
    4】可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
    ***相对mvc,mvvm主要解决了:
    mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
    缺点: 因为使用了dataBinding,增加了大量的内存开销,增加了程序的编译时间(webpack),项目越大内存开销越大。
    c、MVVM的实现主要是三个核心点:
    响应式:vue如何监听data的属性变化
    模板解析:vue的模板是如何被解析的
    渲染:vue模板是如何被渲染成HTML的

    2、单页面应用及其优缺点
    单页应用,即在一个页面里面加载了所有的HTML、JavaScript 和 CSS
    1】优点:
    1).良好的交互体验
    用户不需要重新刷新页面,获取数据也是通过Ajax异步获取,页面显示流畅。
    2).良好的前后端工作分离模式
    单页Web应用可以和RESTful规约一起使用,通过REST API提供接口数据,并使用Ajax异步获取,这样有助于分离客户端和服务器端工作。更进一步,可以在客户端也可以分解为静态页面和页面交互两个部分。
    3).减轻服务器压力
    服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍;
    4).共用一套后端程序代码
    不用修改后端程序代码就可以同时用于Web界面、手机、平板等多种客户端;
    2】缺点:
    1).SEO难度较高
    由于所有的内容都在一个页面中动态替换显示,所以在SEO上其有着天然的弱势,所以如果你的站点对SEO很看重,且要用单页应用,那么就做些静态页面给搜索引擎用吧。
    2).前进、后退管理
    由于单页Web应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理,当然此问题也有解决方案,比如利用URI中的散列+iframe实现。
    3).初次加载耗时多
    为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScript、CSS统一加载,部分页面可以在需要的时候加载。所以必须对JavaScript及CSS代码进行合并压缩处理,如果使用第三方库,建议使用一些大公司的CDN,因此带宽的消耗是必然的。

    3、Vue
    (关键点:渐进式框架,自底向上,只关注视图层,一切皆组件)
    Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
    对于vue而言,一切皆组件(组件系统),因为组件本质就是是可复用的 Vue 实例。vue初始化的时候,在mian.js里面通过Vue.component()创建一个全局组件之后,我们可以new一个Vue实例,然后就把根节点挂载上去。new Vue({ el: ‘#app’ }),然后在这个 Vue 根实例中,把这个组件作为自定义元素来使用。

    4、vue渐进式框架的理解
    每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
    Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。你可以在底层数据逻辑的地方用OO和设计模式的那套理念,也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。

    5、vue.js的两个核心是什么?三要素是什么?
    1】两个核心:双向数据绑定 和 组件系统
    2】三要素:响应式、模板引擎 和 渲染

    6、vue生命周期详解
    1】生命周期
    Vue 实例从创建到销毁的一系列过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
    2】生命周期的作用是什么?
    它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

    Vue所有的生命周期钩子自动绑定在this上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法。这是因为箭头函数绑定了父级上下文,因此this与你期待的Vue实例不同。
    (注:vm.$el 是用于获取和操作Vue实例关联的DOM元素的一个对象)

    1】beforeCreate
    vue实例创建之前,data 和 $el(dom)都没有初始化 全部为 undefined
    应用:可以在此时加一些loading效果,在created 时进行移除(App.vue或者其他组件)

    2】created
    vue实例创建完成,data 初始化完成,但 $el 没有初始化
    应用:如果业务逻辑不涉及到需要页面加载完成之后的话,可以在这里进行 ajax 请求

    3】beforeMount(模板解析中)
    虚拟dom解析成真实dom,并挂载到Vue实例之前~
    data 和 $el 均已存在,template模板已导入渲染函数编译。而当前阶段虚拟dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
    应用:这里实际应用比较少

    4】mounted
    虚拟dom解析成真实dom,并挂载到Vue实例之后~
    模板引擎已被完全解析成html,挂载到Vue实例上,并渲染到页面
    应用:
    1.可以进行ajax请求;
    2.因为dom已经完全渲染出来了,可以在这里进行dom操作。
    注意:若涉及父子组件,父组件mounted完毕以后,子组件还不一定mounted完毕。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted

    5】beforeUpdate
    在数据更新之前调用,发生在虚拟DOM重新渲染之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程,会更新当前组件数据,但未在页面渲染出来。

    6】updated
    data发生变化,触发DOM重新渲染,当这个生命周期函数被调用时,组件 DOM 已经更新完毕,所以你现在可以执行依赖于 DOM 的操作。
    应用:
    任何数据的更新,如果要做统一的业务逻辑处理,可以在这个钩子里面进行。
    例如:
    即时聊天项目,打开当前会话加载完消息后需要自动滚动到窗口最底部。滚动到底部这个操作就可以放在这个钩子函数里面来完成。
    注意:
    a、当实例每次进行数据更新时updated都会执行。
    b、无论是组件本身的数据变更,还是从父组件接收到的 props 或者从vuex里面拿到的数据有变更,都会触发虚拟 DOM 重新渲染和打补丁,并在之后调用 updated。

    7】beforeDestroy 【类似于React生命周期的componentWillUnmount】
    实例销毁之间调用。在这一步,实例仍然完全可用。该钩子在服务端渲染期间不被调用。
    应用:可以在这里清除定时器。

    8】destroyed
    Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染不会被调用

    ***另外还有 keep-alive 独有的生命周期,分别为 activated 和 deactivated
    被keep-alive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数
    1】activated
    keep-alive组件激活时调用。该钩子在服务器端渲染期间不被调用。
    2】deactivated
    keep-alive组件停用时调用。该钩子在服务端渲染期间不被调用。

    ***关于updated钩子函数一个问题:
    data里面数据发生变化,一定会触发updated这个钩子函数吗?
    答:只有data里的变量改变并且要在页面重新渲染完成之后,才会进updated生命周期。只改变data里的值,但是没有再页面上渲染该值的话,并不会触发updated。
    比如data里面某个值传入Null,值是改变了,但是对于页面还说是没有变化的,所以不会触发updated。

    7、生命周期钩子函数可以用箭头函数吗?
    不可以。箭头函数的this指向父级上下文,而生命周期钩子函数的this默认指向Vue实例,强行用箭头函数会导致this指向错误。

    8、this. n e x t T i c k 用 法 和 实 际 应 用 场 景 1 】 原 理 数 据 更 新 − > 视 图 更 新 完 毕 之 后 进 行 的 逻 辑 操 作 v u e 最 大 的 特 点 是 双 向 绑 定 ( 响 应 式 ) , 数 据 发 生 变 化 , 视 图 就 会 更 新 。 但 是 , 视 图 更 新 这 个 操 作 是 异 步 的 。 当 侦 听 到 数 据 发 生 变 化 时 , V u e 将 开 启 一 个 异 步 的 视 图 更 新 队 列 , 视 图 需 要 等 这 个 队 列 中 所 有 数 据 变 化 完 成 之 后 , 再 统 一 进 行 更 新 。 我 们 可 以 使 用 nextTick用法和实际应用场景 1】原理 数据更新->视图更新完毕之后进行的逻辑操作 vue最大的特点是双向绑定(响应式),数据发生变化,视图就会更新。但是,视图更新这个操作是异步的。当侦听到数据发生变化时,Vue将开启一个异步的视图更新队列,视图需要等这个队列中所有数据变化完成之后,再统一进行更新。 我们可以使用 nextTick1>vueVue使nextTick(callback)。这里的回调函数(callback)将在数据更新完成,并且视图更新完毕之后被调用。
    nextTick的底层还是基于setTimeout来实现的,setTimeout本身是宏任务,可以优先执行。
    2】应用场景
    1)如果要在created()钩子函数中进行的DOM操作,由于created()钩子函数中还未对DOM进行任何渲染,所以无法直接操作,需要通过KaTeX parse error: Expected '}', got 'EOF' at end of input: … () { this.nextTick(()=>{
    this.KaTeX parse error: Expected 'EOF', got '}' at position 34: … = "钢铁的翅膀" }̲) } 注:在created(…nextTick()会报错。
    2)在使用某些第三方插件时 ,比如echart 在初始化的时候,由于dom渲染还未完成,因此或造成初始化报错,所以要放在 this. n e x t T i c k 的 回 调 里 面 。 3 ) m o u n t e d 不 会 承 诺 所 有 的 子 组 件 也 都 一 起 被 挂 载 ( 父 组 件 先 m o u n t , 子 组 件 后 m o u n t ) 。 如 果 你 希 望 等 到 整 个 视 图 都 渲 染 完 毕 , 可 以 用 v m . nextTick 的回调里面。 3)mounted 不会承诺所有的子组件也都一起被挂载(父组件先mount,子组件后mount)。如果你希望等到整个视图都渲染完毕,可以用 vm. nextTick3mountedmountmountvm.nextTick 替换掉 mounted:
    mounted: function () {
    this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
    })
    }

    9、vue中组件的data为什么是一个函数
    组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。
    恰好函数具备这个特性,函数内部的局部变量,只有内部感知,不会对外界造成影响。
    ***为什么在大型项目中data需要使用return返回数据呢?
    答:不使用return包裹的数据会在项目的全局可见,会造成变量污染;使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。

    10、父组件传值给子组件遇到的生命周期问题
    项目遇到父组件传值给子组件,子组件监听数据变化可以用watch监听数据变化

    如果要在子组件打印父组件传来的数据必须是在beforeUpdate和updated生命周期才能监听的到
    ***Vue 的父组件和子组件生命周期钩子执行顺序:
    组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
    组件的销毁操作是先父后子,销毁完成的顺序是先子后父。
    1】加载渲染过程
    父组件挂载前准备编译模板的时候,先让子组件编译模板并挂载完毕以后,父组件再挂载。
    父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

    2】子组件更新过程
    父beforeUpdate->子beforeUpdate->子updated->父updated

    3】父组件更新过程
    父beforeUpdate->父updated(跟子没有关系)
    4】销毁过程
    父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

    11、vue打包后会生成哪些文件?
    默认生产 dist 文件夹:
    生产index.html单页面文件
    将组件中的 css 编译合并成一个 app.[hash].css 的文件,
    js 则在合并后又拆解成 了 4 个文件:
    app.[hash].js 包含了所有 components 中的 js 代码
    vendor.[hash].js 包含了生产环境所有引用的 node_modules 中的代码
    mainfest.[hash].js 则包含了 webpack 运行环境及模块化所需的 js 代码
    0.[hash].js 则是 vue-router 使用了按需加载生产的js文件
    static 静态文件夹
    这样拆分的好处是:
    每块组件修改重新编译后不影响其他未修改的 js 文件 的 hash 值,这样能够最大限度地使用缓存,减少 HTTP 的请求数

    12、Vue3.0和Vue2.0的区别
    响应式的变更:
    2用的是Object.defineProperty,3用的是Proxy
    1】默认进行懒观察(lazy observation)
    在 2.x 版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入时造成明显的性能压力。3.x 版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x 的观察者更高效。
    2】更精准的变更通知
    比例来说:2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运行;3.x 版本中,只有依赖那个属性的 watcher 才会重新运行。
    3】3.0 新加入了 TypeScript 以及 PWA 的支持
    4】部分命令发生了变化:
    下载安装 npm install -g vue@cli
    删除了vue list
    创建项目 vue create
    启动项目 npm run serve
    5】默认项目目录结构也发生了变化:
    移除了配置文件目录,config 和 build 文件夹
    移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中
    在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件
    6】代码体积变得更小

    13、vue和react的区别
    1】数据:
      vue:双向数据绑定和单向数据流。双向数据绑定:DOM元素绑定的data值,当发生改变后,vue的响应式机制会自动监听data的变化重新渲染。单向数据流:当父组件给子组件传递数据的时候,子组件只可以读取而不能修改数据。可以用watch监听数据的更改,再赋给父组件的变量。
      react:单向数据流。DOM元素依赖于state,但改变state不会改变渲染好的DOM,通过setState()才能重新渲染。父组件传值到子组件,如果顶级的props变了,会重新渲染所有的子组件。
    2】虚拟DOM:
      vue:计算出虚拟DOM的差异,在渲染的过程中跟踪每个组件的依赖关系,不会重新渲染整个组件树
      react:当应用的状态改变时,重新渲染全部子组件,可以通过shouldComponentUpdate生命周期进行优化
    3】模板和jsx:
      vue:具有单文件组件,可以把html、css、js写在一个vue文件里----MVVM框架
      react:依赖于jsx,在JavaScript中创建DOM----视图层框架
    4】构建工具:
      vue:vue-cli
      react:create-react-app 项目名
    5】app开发
      vue:Weex目前处于开发的状态
      react:React Native能在手机上创建原生应用,React在这方面处于领先位置。
    6】团队支持:
      vue:尤雨溪个人,目前和阿里合作
      react:facebook维护
    7】开发选择
    快速开发客户端页面可以选用vue,复杂的后台管理系统可以用react

    14、两种路由模式
    1】hash模式
    本质:window.location.hash,用来获取或设置页面的标签值。
    a. HTTP请求不包括#,#是用来指导浏览器动作的,对服务器端完全无用,对浏览器而言,就是一个位置标识符
    b.单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页
    c.每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录
    2】history模式
    利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。
    history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如:http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误
    注意:pushState和replaceState,都不会刷新浏览器页面。
    3】两种模式对比
    hash模式由于带有#,导致做微信H5分享的时候,会出一些问题。

    15、router-link和传统a链接的区别
    1】通过a标签进行跳转,页面会被重新渲染,即相当于重新打开一个新的网页,体现为视觉上的“闪烁”(如果是本地的项目基本看不出来)
    2】通过router-link进行跳转不会跳转到新的页面,也不会重新渲染,它会选择路由所指的组件进行渲染,避免了重复渲染的“无用功”。

    16、vue是单向还是双向数据流?
    单向数据流。
    单向数据流指的父组件传值给子组件,子组件不能修改这个值,而父组件修改这个值的话子组件也会受影响,这个影响是单向的,只能从父组件流向子组件,不能反向。
    ng貌似是双向数据流。

    17、Vue组件通信有哪些方式?
    1】父子组件通信
    父->子props,子->父 o n 、 on、 onemit
    获取父子组件实例 p a r e n t 、 parent、 parentchildren
    ref 获取实例的方式调用组件的属性或者方法
    2】兄弟组件通信
    Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue()
    Vuex
    3】跨级组件通信
    Vuex
    a t t r s 、 attrs、 attrslisteners

    18、axios
    1)axios如何封装而成,有无阅读过axios的源码

    2)axios的二次封装
    import axios from ‘axios’;
    import ui from ‘ui’;
    let baseURL;
    //是判断生产环境或开发环境的依据的
    if(process.env.NODE_ENV==‘development’){
    baseURL = ‘http://localhsot:8888/vue/demo1/api/’ //开发环境
    } else {
    baseURL = ‘/xxx’ //生产环境
    }
    // axios.create 创建axios对象,包含baseURL axios.get(“url”)
    const $http = axios.create({
    baseURL,
    })
    //url 路径 params 参数 http://localhsot:8888/vue/demo1/api/a.php?page=3
    export const get = (url,params)=>{
    ui.loading(); //加载效果
    params = params || {};//参数要么有 或 空对象
    return new Promise((resolve,reject)=>{
    // axiso 自带 get 和 post 方法
    $http.get(url,{params,}).then(res=>{ //get请求 url 路径参数
    ui.cancelLoding();
    resolve(res.data);
    }).catch(error=>{
    ui.alert(‘网络异常’);
    })
    })
    }
    export const post = (url,params)=>{
    ui.loading(); //加载效果
    params = params || {};
    return new Promise((resolve,reject)=>{
    $http.post(url,params).then(res=>{
    ui.cancelLoding();
    resolve(res.data);
    }).catch(error=>{
    ui.alert(‘网络异常’);
    })
    })
    }
    3)axios的拦截器
    在请求发送之前,以及数据返回之后,我们都可以对请求的结构以及返回的数据做一个处理,然后在将请求发给后端(如在请求头中增加token),如果是后端返回数据,则可以根据状态码来进行提前的一个提示。
    // 构建axios实例
    const instance = axios.create({
    baseURL: process.env.BASE_API, // 该处url会根据开发环境进行变化(开发/发布)
    timeout: 10000 // 设置请求超时连接时间
    })
    1】request 拦截器
    instance.interceptors.request.use(
    config => {
    console.log(config); // 该处可以将config打印出来看一下,该部分将发送给后端(server端)
    config.headers.token = ‘该处可设置token内容’;
    return config // 对config处理完后返回,下一步将向后端发送请求
    },
    error => { // 当发生错误时,执行该部分代码
    console.log(error); //调试用
    return Promise.reject(error)
    }
    )
    2】response拦截器
    instance.interceptors.response.use(
    response => { // 该处为后端返回整个内容
    const res = response.data; // 该处可将后端数据取出,提前做一个处理
    if (‘正常情况’) {
    return response // 该处将结果返回,下一步可用于前端页面渲染用
    } else {
    alert(‘该处异常’);
    return Promise.reject(‘error’)
    }
    },
    error => {
    console.log(error),
    return Promise.reject(error)
    }
    )
    3)注意,axios 是 取不到 cookie的
    1】开发的时候,存在跨域
    如果要发送Cookie,后端的Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传
    前端vue设置proxyTable代理
    后端的Access-Control-Allow-Origin不能为*
    注意:http 和 https 也算是跨域!

    19、mixin
    混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
    var mixin = {
    created: function () {
    console.log(‘混入对象的钩子被调用’)
    }
    }
    new Vue({
    mixins: [mixin],
    created: function () {
    console.log(‘组件钩子被调用’)
    }
    })
    上面的例子:
    执行created优先调用混入对象的created
    但是data()里面数据冲突的时候,以组件的data为准;同样,methods方法里面的fun同名,也是以组件内的为准

    1】全局混入
    类似上面例子,new实例化Vue对象里面引入mixin
    实际应用场景:微信H5和微信小程序的分享功能(要求每个页面都可以转发分享)
    2】选项合并
    可以在单个组件里面引入 mixin

    20、Vue.extend
    Vue.extend是Vue实例的拓展,可以用于开发一些独立的组件。
    1】基本用法
    参数:Vue.extend(options),options包含template 和 data
    结合$mount,可以把自定义的标签挂载到指定的元素上面

    2】源码剖析
    extend方法返回的其实是1个构造函数,而且继承自Vue,因此extend方法返回的是Vue的1个子类。
    3】应用场景
    所有内容都是在 #app 下渲染,注册组件都是在当前位置渲染。如果我要实现一个类似于 window.alert() 提示组件要求像调用 JS 函数一样调用它,该怎么办?
    这时候,Vue.extend + vm.$mount 组合就派上用场了

    21、Vue.use()
    一般是用于全局注册插件
    1】用法
    a、vue2.x使用Vue.use()
    import Vue from ‘vue’;
    Vue.use(xxx);
    b、vue3.x使用app.use()
    import { createApp } from ‘vue’;
    import App from ‘./App.vue’;
    const app = createApp(App);
    app.use(xxx);
    2】参数
    Vue.use(options)
    options为1个对象或者函数,并且必须带有install 方法,通过install 方法注册到全局
    a、对象
    const demo = {
    // 参数为对象时,需要提供install方法
    install: (Vue) => {
    Vue.prototype. T o a s t = ( ) = > c o n s o l e . l o g ( ′ 全 局 t o a s t 提 示 ′ ) ; / / t o a s t 提 示 , 通 过 t h i s . Toast = () => { console.log('全局toast提示') }; // toast提示,通过this. Toast=()=>console.log(toast);//toast,this.Toast调用
    Vue.prototype. r e q u e s t = ( ) = > c o n s o l e . l o g ( ′ 全 局 r e q u e s t 请 求 ′ ) ; / / r e q u e s t 请 求 , 通 过 t h i s . request = () => { console.log('全局request请求') }; // request请求,通过this. request=()=>console.log(request);//request,this.request调用
    }
    }
    export default demo;
    b、函数(本身作为1个install方法)
    const common = (Vue) => {
    // 定义一些vue中常用的全局方法
    Vue.prototype. T o a s t = ( ) = > c o n s o l e . l o g ( ′ 全 局 t o a s t 提 示 ′ ) ; / / t o a s t 提 示 , 通 过 t h i s . Toast = () => { console.log('全局toast提示') }; // toast提示,通过this. Toast=()=>console.log(toast);//toast,this.Toast调用
    Vue.prototype. r e q u e s t = ( ) = > c o n s o l e . l o g ( ′ 全 局 r e q u e s t 请 求 ′ ) ; / / r e q u e s t 请 求 , 通 过 t h i s . request = () => { console.log('全局request请求') }; // request请求,通过this. request=()=>console.log(request);//request,this.request调用
    };
    export default common;
    3】Vue.use源码
    a、首先先判断插件plugin是否是对象或者函数:
    b、判断vue是否已经注册过这个插件,如果已经注册过,跳出方法
    c、取Vue.use()里面的参数,通过toArray将传入的参数整理成数组
    d、判断插件是否有install方法,如果有就执行install()方法;没有就直接把plugin当Install执行

    22、vue插件机制
    1】插件通常用来为 Vue 添加全局功能:比如添加全局指令vue-touch,或者全局混入一些组件选项比如vue-router
    2】通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成
    3】开发插件
    Vue.js 的插件应该暴露1个 install 方法。这个方法的第1个参数是 Vue 构造器,第2个参数是1个可选的选项对象:
    MyPlugin.install = function (Vue, options) {
    Vue.myGlobalMethod = function () { // 1. 添加全局方法或 property
    // 逻辑…
    }
    Vue.directive(‘my-directive’, { // 2. 添加全局资源
    bind (el, binding, vnode, oldVnode) {
    // 逻辑…
    }
    })
    Vue.mixin({ // 3. 注入组件选项
    created: function () {
    // 逻辑…
    }
    })
    Vue.prototype.$myMethod = function (methodOptions) { // 4. 添加实例方法
    // 逻辑…
    }
    }

    23、自定义指令
    1】创建局部指令
    var app = new Vue({
    el: ‘#app’,
    data: {
    },
    // 创建指令(可以多个)
    directives: {
    // 指令名称
    dir1: {
    inserted(el) {
    // 指令中第一个参数是当前使用指令的DOM
    console.log(el);
    console.log(arguments);
    // 对DOM进行操作
    el.style.width = ‘200px’;
    el.style.height = ‘200px’;
    el.style.background = ‘#000’;
    }
    }
    }
    })
    2】全局指令
    Vue.directive(‘dir2’, {
    inserted(el) {
    console.log(el);
    }
    })
    3】指令的使用

    24、插槽
    1】单个插槽 | 默认插槽 | 匿名插槽
    匿名插槽就是可以在父组件中的子组件的标签中直接添加内容。
    用法:
    在子组件埋入,父组件引用子组件的时候,可以在子组件标签的内部填入任何元素。
    2】具名插槽
    具名插槽就是一个拥有name属性的插槽,具名插槽可以在同一组件中多次使用。
    用法:
    子组件:
    父组件:

    按钮

    3】作用域插槽
    作用域插槽就是一个可以携带数据的具名插槽,称为作用域插槽。
    用法:
    子组件:
    父组件:

    {{scope.message}}

    25、组件的自我调用
    1】实际用途
    组件自我调用,一般都是用于实现递归展示。
    比如类似这种嵌套的数据结构,每一层的结构都基本类似,在不清楚有多少层的情况下,利用组件的自我调用可以解决。
    dataList:[
    {
    name:‘名称1’,
    children:[
    {
    name:‘名称1-1’
    children:[
    {
    name:‘名称1-1-1’,
    children:[
    //…
    ]
    }
    ]
    }
    ]
    }
    ]
    2】用法
    利用name这个属性即可实现
    export default {
    name: “myTree”,

    },
    }

    26、计算属性computed与methods
    1】computed与methods的区别
    a、computed计算属性中定义的是属性而不是函数,所以使用时直接用{{xxx}}
    methods中定义的是函数,因此使用时需要{{xxx()}}
    b、计算属性computed被使用时会进行缓存,如果需要多次使用,则只需要调用1次
    而methods中的函数无缓存,如果需要使用n次,则需要调用n次
    2】为什么使用计算属性时不用加()
    计算属性的实质为属性,其中定义了set()方法和get()方法

    一般使用中不需要set方法,我们只需要get方法,因此计算属性一般为“只读属性”
    去掉无用的set方法后,computed属性简写为我们常见的方式:

    只是形式上看起来像函数,实质上computed计算属性是属性,所以不要加()。

    27、Vue路由懒加载原理
    组件的按需加载也是这个原理
    1】定义
    路由懒加载也可以叫做路由组件懒加载,原理: Vue 的异步组件 和 Webpack 的代码分割。
    const Foo = () => import(‘./Foo.vue’)
    const router = new VueRouter({
    routes: [
    { path: ‘/foo’, component: Foo }
    ]
    })
    2】Webpack 的代码分割
    (详情见webpack篇)
    通过Webpack编译打包后,会把每个路由组件的代码分割成一一个js文件(chunk块),初始化时不会加载这些js文件,只当激活路由组件才会去加载对应的js文件。

    3】Vue 的异步组件
    异步组件主要通过 代码分割 和 延迟加载 来实现。
    a、静态导入模块
    import utils from ‘./utils’

    b、动态导入模块
    1)a、使用vue-router中需求的’syntax-dynamic-import’插件,然后在webpack的plugin里面配置这个插件;b、在webpack配置文件的出口处,配置chunkFilename属性;
    这样在代码内部,使用import语法。同时,在import语法使用的地方,指定对应的模块名webpackChunkName。
    2)语法:通过箭头函数+直接import相关的模块
    动态导入是一个返回Promise的函数,这样可以延迟加载相应的模块
    () => import(/* webpackChunkName: ‘ImportFunc’ */ ‘./components/Tooltip’)
    3)注意
    没有指定webpackChunkName,每个组件打包成一个js文件;
    指定了相同的webpackChunkName,会合并打包成一个js文件,把组件按组分块。

    c、也可以通require导入
    component: resolve => require([‘@/components/home’], resolve)
    这里的component配置返回了一个Promise函数

    28、父组件监听子组件的生命周期
    可以在父组件引用子组件时通过 @hook 来监听即可
    // Parent.vue
    <Child @hook:mounted=“doSomething” >
    doSomething() {
    console.log(‘父组件监听到 mounted 钩子函数 …’);
    },
    // Child.vue
    mounted() {
    console.log(‘子组件触发 mounted 钩子函数 …’); //先打印
    },
    // 以上输出顺序为:
    // 子组件触发 mounted 钩子函数 …
    // 父组件监听到 mounted 钩子函数 …
    @hook方法不仅仅是可以监听 mounted,其它的生命周期事件,例如:created,updated 等都可以监听。

    29、父子组件获取对方的dom
    1】父组件获取子组件的dom
    this.$refs.xxx

    2】子组件获取父组件的dom this.$parent.数据 this.$parent.方法
  • 相关阅读:
    mysql开启慢查询日志及死锁排查
    php ci 框架准备工作
    文心一言 VS 讯飞星火 VS chatgpt (102)-- 算法导论9.3 8题
    商业化广告--体系学习-- 3 -- 行业蓝图篇 -- 广告主、媒体、第三方检测
    java计算机毕业设计校园酒店管理系统源码+系统+mysql数据库+lw文档
    【力扣C语言】每日一题
    C语言中,如何判断两个数组是否包含相同元素?
    【CSS】transition、transform以及animation
    【会议征稿,CPS出版】第四届管理科学和软件工程国际学术会议(ICMSSE 2024,7月19-21)
    IE让我首次遭受了社会的毒打
  • 原文地址:https://blog.csdn.net/qq_37546835/article/details/125476869