# 技术栈知识点巩固——Vue

技术栈知识点巩固——Vue

# Vue 知识点总结

# Vue 多模块管理路由(Router)、请求(Axios)

# Vue 组件开发打包、Vue 项目打包、js库组件库打包使用

Vue 概念

  • Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

Vue核心

  • Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。

MVVM 模型

  • Mode-View-ViewModel
  • Model代表数据模型、View代表UI组件、ViewModelViewModel层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据

Vue 生命周期

  • Vue实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。
    请添加图片描述

beforeCreate(创建前)

  • 组件实例被创建之初,组件的属性生效之前

created(创建后)

  • 组件实例已经完全创建,属性也绑定,真实dom还没有生成,$el还不可用

beforeMount(挂载前)

  • 在挂载开始之前被调用:相关的render函数被首次调用

mounted(挂载后)

  • el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子

beforeUpdate(更新前)

  • 组件数据更新之前调用,真实DOM还没被渲染

updated(更新后)

  • 组件数据更新之后

activated(激活前)

  • keep-alive专属,组件被激活时调用

deactivated(激活后)

  • keep-alive专属,组件被销毁时调用

beforeDestory(销毁前

  • 组件销毁前调用

destoryed(销毁后)

  • 组件销毁前调用

Vue 父向子传值

  • 遵守单向数据流原则

  • prop向下传递

Vue 子向父传值

  • 遵守单向数据流原则

  • 事件向上传递,使用$on(evntName)监听事件;使用$emit(eventName,optionalPayload)触发事件。另外,父组件可以在使用子组件的地方直接用v-on来监听子组件触发的事件。

父子组件生命周期顺序

  • 执行顺序:父组件先创建,然后子组件创建;子组件先挂载,然后父组件挂载,即父beforeCreate-> 父create -> 子beforeCreate-> 子created -> 子mounted -> 父mounted

非父子组件通信

  • 使用EventBus

  • EventBus.js

import Vue from 'vue'
export default new Vue()
  • 发送数据
import eventBus from './EventBus'

methods: {
    pushMsg(){
        // 通过事件总线发送消息
        eventBus.$emit('pushMsg',this.childNum++)
    }
}
  • 接收数据
mounted() {
    // 通过事件总线监听消息
    eventBus.$on('pushMsg', (children1Msg) => {
        this.msg = children1Msg
    })
}

Vue.$nextTick()

  • 参数:{Function}[callback]
  • 用法:将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法Vue.nextTick一样,不同的是回调的 this 自动绑定到调用它的实例上。

示例

<!DOCTYPE html>
<html>

<body>
    <head>
        <script src="./js/vue.js"></script>
    </head>
    <div id="app">
        <p id="msg">{{message}}</p>
        <button @click="change">更新</button>
    </div>
</body>

</html>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        },
        methods: {
            change() {
                this.message = 'This is new message!';
                console.log('not nextTick():', document.getElementById("msg").innerHTML);
            }
        }
    })
</script>
  • console.log预期应该输出not nextTick():This is new message!但是输出的是 not nextTick(): Hello Vue!

  • Vue在更新DOM的时候,是异步执行的。只要监听到数据变化,vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环tick中,Vue 刷新队列并执行实际 (已去重的) 工作。

使用

  • 立即输出更新后的值
change(){
    this.message = 'This is new message!';
    this.$nextTick(()=>{
        console.log('use nextTick():',document.getElementById("msg").innerHTML);
    })
    console.log('not nextTick():',document.getElementById("msg").innerHTML);
}
  • 使用this.$nextTick()之所以能获取到更新后的值,并不是改变了vue的渲染流程,而是改变了获取最新值的时间,并不是立即获取,而是等vue渲染完后再获取,即异步获取

Computed

  • 支持缓存,只有依赖的数据发生变化,才会重新计算
  • 不支持异步,当Computed中有异步操作时,无法监听数据的变化
  • Computed的值默认会走缓存
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed
  • 如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。

Watch

  • 不支持缓存,数据变化时,触发相应的操作
  • 支持异步监听
  • 监听的函数接收两个参数,第一个时参数的新值,第二个是变化之前的值
  • 监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作,函数有两个的参数:
    • immediate:组件加载立即触发回调函数
    • deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。
// 监听基本数据类型
watch: {
    value () {
        // do something
    }
}
// 监听引用数据类型
watch: {
    obj: {
       handler () { // 执行回调
           // do something
       },
       deep: true, // 是否进行深度监听
       immediate: true // 是否初始执行handler函数
    }
}

常见的事件修饰符

  • .stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;
  • .prevent:等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
  • .capture:与事件冒泡的方向相反,事件捕获由外到内;
  • .self:只会触发自己范围内的事件,不包含子元素;
  • .once:只会触发一次。

v-show、v-if

  • v-show隐藏则是为该元素添加css--display:nonedom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除

  • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换

  • v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染

  • v-showfalse变为true的时候不会触发组件的生命周期

  • v-iffalse变为true的时候,触发组件的beforeCreatecreatebeforeMountmounted钩子,由true变为false的时候触发组件的beforeDestorydestoryed方法

  • v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

Vue 动态组件

  • Vue.js 提供了一个特殊的元素 <component> 用来动态地挂载不同的组件 使用 is 属性来选择要挂载的组件。
<template>
  <div>
    <h1>vue 动态组件使用</h1>
    <button @click="changeView('A')">切换到组件A</button>
    <button @click="changeView('B')">切换到组件B</button>
    <button @click="changeView('C')">切换到组件C</button>
    <component :is="currentView"></component>
  </div>
</template>
<script>
export default {
  components: {
    componentA: {
      template: '<div>组件A</div>'
    },
    componentB: {
      template: '<div>组件B</div>'
    },
    componentC: {
      template: '<div>组件C</div>'
    }
  },
  data () {
    return {
      currentView: 'componentA'
    }
  },
  methods: {
    changeView (val) {
      this.currentView = 'component' + val
    }
  }
}
</script>

keep-alive

  • keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。
  • 常用的两个属性include/exclude,允许组件有条件的进行缓存。
  • 两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。
  • keep-alive的中还运用了LRU(Least Recently Used)算法。

不需要响应式的数据应该怎么处理

// 方法一:将数据定义在data之外
data () {
    this.list1 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
    return {}
}

// 方法二:Object.freeze()
data () {
    return {
        list1: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
    }
}

Vue中双向数据绑定实现

  • vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;核心:关于VUE双向数据绑定,其核心是 Object.defineProperty() 方法。
  • 使用Object.defineProperty()来定义属性的set函数,属性被赋值的时候,修改Inputvalue值以及span中的innerHTML;然后监听inputkeyup事件,修改对象的属性值,即可实现这样的一个简单的数据双向绑定。
<!DOCTYPE html>
<html>
  <head>
    <script src="./js/vue.js"></script>
  </head>
  <body>
    <h2>Vue 双向绑定</h2>
    <input type="text" id="textInput" />
    输入:<span id="textSpan"></span>
  </body>
  <script>
    let obj = {};
    let textInput = document.getElementById("textInput");
    let textSpan = document.getElementById("textSpan");

    Object.defineProperty(obj, "foo", {
      set: function (newValue) {
        textInput.value = newValue;
        textSpan.innerHTML = newValue;
      },
    });

    textInput.addEventListener("keyup", function (e) {
      obj.foo = e.target.value;
    });
  </script>
</html>

Vue 优化

编码阶段

  • 尽量减少data中的数据,data中的数据都会增加gettersetter,会收集对应的watcher

  • v-ifv-for不能连用

  • 如果需要使用v-for给每项元素绑定事件时使用事件代理

  • SPA 页面采用keep-alive缓存组件

  • 在更多的情况下,使用v-if替代v-show

  • key保证唯一

  • 使用路由懒加载、异步组件

  • 防抖、节流

  • 第三方模块按需导入

  • 长列表滚动到可视区域动态加载

  • 图片懒加载

SEO优化

  • 预渲染
  • 服务端渲染SSR

打包优化

  • 压缩代码
  • Tree Shaking/Scope Hoisting
  • 使用cdn加载第三方模块
  • 多线程打包happypack
  • splitChunks抽离公共文件
  • sourceMap优化

v-model

  • v-model用于表单数据的双向绑定,是一个语法糖
  • v-bind绑定一个value属性
  • v-on指令给当前元素绑定input事件
<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />

vue组件中data是一个函数

  • 组件中的data是一个函数数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,每个组件都会有自己私有的数据空间,他们只负责各自维护的数据,不会造成混乱。

vue-router 钩子

全局路由钩子

  • router.beforeResolve : 在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,该钩子函数就被调用
  • router.afterEach : 路由改变后的钩子
beforeEach(to,from,next)
afterEach(to,from,next)

单个路由钩子

  • 可以在路由配置上直接定义 beforeEnter
cont router = new Router({
   routes: [
       {
           path: '/file',
           component: File,
           beforeEnter: (to, from ,next) => {
               // do someting
           }
       }
   ]
});

组件内路由钩子

  • beforeRouteEnter 不能获取组件实例 this,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例 this
methods: {},
beforeRouteLeave (to, from, next) {}
  • beforeRouteEnter 在进入当前组件对应的路由前调用
  • beforeRouteUpdate 在当前路由改变,但是该组件被复用时调用
  • beforeRouteLeave 在离开当前组件对应的路由前调用

单向数据流和双向数据流

  • 单向数据流是指数据只能从父级向子级传递数据,子级不能改变父级向子级传递的数据。

  • 双向数据流是指数据从父级向子级传递数据,子级可以通过一些手段改变父级向子级传递的数据。

  • 比如用v-model.sync来实现双向数据流。

vue-loader

  • 基于webpack的一个的loader,解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理,核心的作用,就是提取,划重点。

Vue属性改变页面不刷新

  • Vue 不允许在已经创建的实例上动态添加新的响应式属性若想实现数据与视图同步更新,可采取下面三种解决方案:

  • Vue.set()

  • Object.assign()

  • $forcecUpdated()

  • 如果为对象添加少量的新属性,可以直接采用Vue.set()

  • 如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象

  • 如果你实在不知道怎么操作时,可采取$forceUpdate()进行强制刷新 (不建议)

Vue mixin 使用

  • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

  • 不同组件中的mixin是相互独立的!

局部混入

  • index.js
export const mixins = {
  data () {
    return {
      msg: 'vue mixin 测试'
    }
  },
  computed () {},
  created () {
    console.log('mixin 中 created 生命周期函数')
  },
  mounted () {
    console.log('mixin 中 mounted生命周期函数')
  },
  methods: {
    clickMe () {
      console.log('mixin 中 点击事件')
    }
  }
}
  • mixin测试页面
<template>
  <div>
    <el-button @click="clickMe">点击按钮</el-button>
  </div>
</template>
<script>
import { mixins } from './index.js'
export default {
  name: 'mixin-vueone',
  mixins: [mixins],
  components: {},
  data () {
    return {
    }
  },
  created () {
    console.log('组件调用 mixin 数据', this.msg)
  },
  mounted () {
    console.log('我是组件的 mounted 生命周期函数')
  },
  methods: {
  }
}
</script>

全局混入

  • main.js
import { mixins } from "./mixin/index";
Vue.mixin(mixins);
  • 谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。

优点

  • 提高代码复用性
  • 无需传递状态
  • 维护方便,只需要修改一个地方即可

缺点

  • 命名冲突
  • 滥用的话后期很难维护
  • 不好追溯源,排查问题稍显麻烦
  • 不能轻易的重复代码

插槽

  • 在一个组件标签中,加入一些内容,那就必须要在组件内声明slot元素,否则不会被渲染出来。

默认插槽

  • 子组件
<template>
  <div>
    <h3>{{ title }}</h3>
    <slot name="center">center 部分</slot>
    <slot name="fotter">fotter 部分</slot>
  </div>
</template>

<script>
export default {
  name: 'childvueone',
  data () {
    return {

    }
  },
  props: ['title', 'listData']
}
</script>
  • 父组件
<template>
  <div>
    <childvueone title="测试1">
      <span slot="center">center 的内容1</span>
      <a slot="fotter">更多</a>
    </childvueone>

    <childvueone title="测试2">
      <span slot="center">center 的内容</span>
      <div slot="fotter">
        <span>插槽内容2</span>
      </div>
    </childvueone>
  </div>
</template>

<script>
import childvueone from './childvue-one.vue'
export default {
  components: {
    childvueone
  },
  data () {
    return {

    }
  }
}
</script>

具名插槽

  • 没有使用name属性的slot插槽就叫做匿名插槽,也被称为默认插槽

作用域插槽

  • 作用域插槽是一种特殊类型的插槽,用作一个(能被传递数据的)可重用模板,来代替已经渲染好的元素。利用 slot 标签将子组件的数据传递到分发的内容上,类似于父子组件传值的prop传递数据。

Mustache表达式使用

  • 双花括号{{}} 就是 mustache语法,用于展示data中的内容,mustache 中可以出现任意的 JS表达式;

  • 表达式{{}}只能从数据对象data中获取数据;

  • mustache中不能出现语句,比如:if () {} / for(var i =0 ...) {} / var num = 1;

  • Mustache 语法不能作用在 HTML 元素的属性上;

ref属性

  • 获取dom元素/组件:标签上添加ref属性,this.$refs.ref属性值获取该dom元素/组件
  • this.$refs.ref属性值.变量名获取组件中的数据
  • this.$refs.ref属性值.方法名()获取组件中的方法

$parent 和 $children

  • this.$parent获取父组件
  • $children由于子组件的个数不确定 返回的是一个数组 ,不是对象
  • this.$children[0]获取第一个子组件

路由模式

  • hash模式:通过#号后面的内容的更改,触发hashchange事件,实现路由切换
  • history模主要是通过history ApipushState()replaceState()两个方法来实现的.pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。
history.go(-2);//后退两次
history.go(2);//前进两次
history.back(); //后退
hsitory.forward(); //前进

Vue template 编译过程

  • 解析template生成ast(抽象语法树)
  • optimize,对AST进行优化,标注静态节点
  • generate,根据AST生成render函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

全栈程序员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值