「Vue自我检验」Vue 核心基础知识点,你全了解吗?

前置知识

学习Vue之前要掌握的 JavaScript基础知识?

  • ES6语法规范
  • ES6模块化
  • 包管理器
  • 原型、原型链
  • 数组常用方法
  • axios
  • promise

文章目录

  • 前置知识
  • Vue核心基础
    • 1.1 MVVM
    • 1.2 MVVM 的工作原理
  • Vue 响应式基础
    • 1. 数据代理
      • `Object.defineProperty()` 的使用
      • 何为数据代理
      • Vue 中的数据代理
    • 2. Vue 监测数据的原理
      • Vue 监测对象数据
      • Vue 监测数组
  • 插值语法
  • 1. 属性绑定指令 v-bind
  • 2. 双向绑定指令 v-model
      • v-model 基础用法
      • v-model 指令修饰符
  • 3. model 收集表单数据
  • 事件绑定指令 v-on
      • v-on 基础用法
      • 事件参数对象
      • 事件修饰符
      • 按键修饰符
  • 条件渲染指令
      • 基础用法
      • v-if 和 v-show 的区别
    • 列表渲染指令 v-for
  • 其它内置指令
      • v-text
      • v-html
      • v-cloak
      • v-once
      • v-pre
  • 过滤器
      • 基本使用
      • 连续调用多个过滤器
      • 过滤器传参
  • computed 计算属性
  • watch 侦听器
  • 动态绑定 class 和 style
      • 动态绑定 class 类名
      • 动态绑定 style 样式
  • vue 生命周期

Vue核心基础

1.1 MVVM

  • MVVM 是Vue实现属数据驱动视图双向数据绑定的核心原理。它把每个HTML 都拆分了三个部分:

「Vue自我检验」Vue 核心基础知识点,你全了解吗?_第1张图片

在MVVM中:

  • Model 代表当前页面渲染时所依赖的数据源
  • View 表示当前页面所渲染的DOM 结构
  • ViewModel 表示Vue 的实例,它时MVVM的实例

1.2 MVVM 的工作原理

1、 ViewModel 会监听数据源的变化,当数据源变化后会同步更新到View的视图中

2、随后ViewModel会监听View的DOM的变化,当View变化后会同步变化到Model的数据源中

官网传送门(opens new window)

Vue 是动态构建用户界面的渐进式 JavaScript 框架

Vue 借鉴 Angular 的模板和数据绑定技术,React 的组件化和虚拟 DOM 技术

Vue 响应式基础

1. 数据代理

Object.defineProperty() 的使用

let person = {
  name: 'Vue',
  sex: 'none',
}
let number = 19

// 配置一
// 参数:对象、属性名、配置
Object.defineProperty(person, 'age', {
  // 属性值
  value: 21,
  // 属性是否可修改
  writable: true,
  // 属性是否可枚举(遍历)
  enumerable: true,
  // 属性是否可删除
  configurable: true,
})

Object.keys(person)

// 配置二
// getter、setter 不能和 value、writable 同时指定
Object.defineProperty(person, 'age', {
  enumberable: true,
  configurable: true,

  get() {
    console.log('age 属性被读取')
    return number
  }

  set(value) {
    console.log('age 属性被修改', value)
    number = value
  }
})

何为数据代理

数据代理:通过一个对象对另一个对象的属性进行操作

let obj = { a: 21 }
let obj2 = { b: 10 }

Object.defineProperty(obj2, 'a', {
  get() {
    return obj.a
  }
  set(value) {
    obj.a = value
  }
})

obj2.a // 21
obj2.a = 1000
obj.a // 1000

Vue 中的数据代理

「Vue自我检验」Vue 核心基础知识点,你全了解吗?_第2张图片

Vue 中通过 vm 实例对象代理对 data 对象属性的操作,让我们更方便操作 data 中的数据。

data 中的数据实际上被存在 vm._data 属性上,如果不进行代理,使用起来很不方便。

通过 Object.defineProperty() 给 vm 添加属性,并且指定 getter 和 setter,通过 getter 和 setter 访问和修改 data 对应是属性。

2. Vue 监测数据的原理

监测数据,即 Vue 是如何监听数据发生变化,从而重新解析模板渲染页面的。Vue 会监测 data 中所有层级的数据。

Vue 监测对象数据

  • 原理:通过 Object.defineProperty() 为属性添加 gettersetter ,对属性的读取、修改进行拦截,即数据劫持

  • 存在问题:

    • 对象新增加的属性,默认不做响应式处理
    • 对象删除属性,也不是响应式的
  • 解决办法,使用如下

    API (opens new window):

    • Vue.set(target, propertyName/index, value)
    • vm.$set(target, propertyName/index, value)
    • Vue.delete(target, propertyName/index)
    • vm.$delete(target, propertyName/index)
  • Vue.set()vm.$set() 不能给 vm 或 vm 的根数据对象添加属性(即 data)

// 简单模拟实现对象的数据监测,Vue 更完善
// Vue 通过 vm.name 即可修改
// Vue 实现深层监听
let person = {
  name: 'Vue',
  age: 99
}

function Observer(obj) {
  const keys = Object.keys(obj)
// 给对象的属性全部做一次代理,实现响应式
  keys.forEach(key => {
    Object.defineProperty(this, key, {
      get() {
        return obj[key]
      },
      set(value) {
        console.log('数据被修改,重新解析模板...')
        obj[key] = value
      }
    })
  })
}

let vm = {}
let observer = new Observer(person)
vm._data = observer  // vue 把数据放到_data中
console.log(observer.name); // 通过代理后的对象可以直接监听数据 输出 Vue

Vue 监测数组

  • 原理:通过重写数组的 API 实现拦截:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
  • 7 个 API 之所以是响应式的,是因为 Vue 对这些方法进行了包裹 (opens new window),即二次封装。做了两件事:调用对应的原生方法更新数组 & 重新解析模板更新页面
  • 存在问题:
    • 直接通过数组下标修改是非响应式的(opens new window)
  • 解决办法:
    • 使用 7 个 API 修改数组
    • Vue.set()vm.$set()
    • Vue.delete()vm.$delete()
  • 思否文章

插值语法

<p>用户名:{{ username }}p>
<p>密码{{ password }}p>


<p>{{ flag ? 111 : 000}}p>
data() {
  return {
    username: 'docsify',
    password: 55520,
    flag: true
  }
}

1. 属性绑定指令 v-bind

<input type="text" v-bind:placeholder="desc" />


<img :src="url" alt="这是一张图片" />


<div :id="'hello' + 1">div>
data() {
  return {
    desc: '请输入用户名',
    url: 'www.baidu.com',
    name: 'hello'
  }
}

2. 双向绑定指令 v-model

v-model 用于表单元素如 inputtextareaselect

v-model 基础用法

<p>{{ username }}p>
<input type="text" v-model:value="username" />
<input type="text" v-model="username" />

<p>{{ province }}p>
<select v-model="province">
  <option value="">请选择option>
  <option value="1">北京option>
  <option value="2">上海option>
  <option value="3">广州option>
select>

v-model 指令修饰符

修饰符 作用 示例
.number 将用户输入转为数值类型
.trim 删除输入的首尾空白字符
.lazy 当失去焦点时,才更新数据,类似防抖

3. model 收集表单数据

  • ,收集的是 value 值,用户输入的就是 value 值。
  • ,收集的是 value 值,且要给标签配置 value 值。
    • 没有配置 value 属性,收集的就是 checked
    • 配置了 value 属性:
      • v-model 的初始值是非数组,那么收集的就是 checked
      • v-model 的初始值是数组,那么收集的的就是 value 组成的数组
<div id="root">
  <form @submit.prevent="demo">
    账号:<input type="text" v-model.trim="userInfo.account" />

    密码:<input type="password" v-model="userInfo.password" />

    年龄:<input type="text" v-model.number="userInfo.age" />

    性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="male" /><input type="radio" name="sex" v-model="userInfo.sex" value="female" />

    爱好: 学习<input type="checkbox" v-model="userInfo.hobby" value="study" />

    打游戏<input type="checkbox" v-model="userInfo.hobby" value="game" />

    吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat" />

    所属校区
    <select v-model="userInfo.city">
      <option value="">请选择校区option>
      <option value="beijing">北京option>
      <option value="shanghai">上海option>
      <option value="shenzhen">深圳option>
      <option value="wuhan">武汉option>
    select>

    其他信息:
    <textarea v-model.lazy="userInfo.other">textarea>
    <input type="checkbox" v-model="userInfo.agree" />阅读接受协议
    <button>提交button>
  form>
div>
data() {
  return {
    userInfo:{
      account:'',
      password:'',
      age:18,
      sex:'female',
      hobby:[],
      city:'beijing',
      other:'',
      agree:''
    }
  }
},
methods: {
  demo() {
    console.log(JSON.stringify(this.userInfo))
  }
}

事件绑定指令 v-on

v-on 基础用法

<p>count的值:{{ count }}p>
<button v-on:click="add">+1button>


<button @click="add">+1button>
data() {
  return {
    count: 1
  }
},
methods: {
  add() {
    this.count++
  }
}

事件参数对象

如果事件处理函数没有传参,则默认会传一个时间参数对象 $event ,通过它可以获取触发事件的元素,并进行相关操作。

methods: {
  add(e) {
    e.target.style.backgroundColor = 'red'
    this.count++
  }
}

如果事件处理函数传递参数了,则默认的 $event 会被覆盖,需要手动进行传递。

<button @click="add(2, $event)">+1button>
methods: {
  add(step, e) {
    e.target.style.backgroundColor = 'red'
    this.count += step
  }
}

事件修饰符

事件修饰符 说明
.prevent 阻止默认行为,如 a 链接跳转、表单提交
.stop 阻止事件冒泡
.once 绑定的事件只触发 1 次
.capture 以捕获模式触发事件处理函数
.self 只有在 event.target 是当前元素自身时触发事件处理函数
.passive 事件的默认行为立即执行,无需等待事件回调执行完毕
<a href="www.baidu.com" @click.prevent="fn">阻止链接跳转a>

<div @click.stop="handleClick">阻止事件冒泡div>



如果回调比较耗时,那么会等一段时间才发生滚动。 添加 .passive 后,则先进行滚动再执行回调。

按键修饰符

  1. Vue 中常用的按键别名:
  • 回车 => enter
  • 删除 => delete (捕获“删除”和“退格”键)
  • 退出 => esc
  • 空格 => space
  • 换行 => tab (特殊,必须配合 keydown 去使用)
  • 上 => up
  • 下 => down
  • 左 => left
  • 右 => right
  1. Vue 未提供别名的按键,可以使用按键原始的 key 值去绑定,但注意要转为 kebab-case(短横线命名)

  2. 系统修饰键(用法特殊):ctrl、alt、shift、meta(即 win 键)

  • 配合 keyup 使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
  • 配合 keydown 使用:正常触发事件。
  1. 可使用 keyCode 去指定具体的按键,此法不推荐,因为 keyCode 以后可能废除

  2. Vue.config.keyCodes.自定义键名 = 键码 ,可以去定制按键别名

<input type="text" @keyup.enter="submit" />
<input type="text" @keyup.esc="back" />
<input type="text" @keydown.tab="showInfo" />
<input type="text" @keyup.caps-lock="showInfo" />

<input type="text" @keyup.huiche="showInfo" />
<input type="text" @keyup.13="showInfo" />  // 回车键
<script>
  Vue.config.keyCodes.huiche = 13
script>

条件渲染指令

基础用法

<p v-if="status === 200">successp>
<p v-else-if="status === 201">xxxp>
<p v-else>yyyp>

<p v-show="status === 404">errorp>


<template v-if="status === 200">
  <p>111p>
  <p>222p>
  <p>333p>
template>

v-if 和 v-show 的区别

实现原理不同:

  • v-if 通过创建或删除 DOM 元素来控制元素的显示与隐藏
  • v-show 通过添加或删除元素的 style="display: none" 样式来控制元素的显示与隐藏

性能消耗不同:

  • v-if 切换开销更高,如果运行时条件很少改变,使用 v-if 更好
  • v-show 初始渲染开销更高,如果切换频繁,使用 v-show 更好

原来在 patchVnode 过程中,内部会对执行 v-show 指令对应的钩子函数 update,然后它会根据 v-show 指令绑定的值来设置它作用的 DOM 元素的 style.display 的值控制显隐。

因此相比于 v-if 不断删除和创建函数新的 DOM,v-show 仅仅是在更新现有 DOM 的显隐值,所以 v-show 的开销要比 v-if 小的多,当其内部 DOM 结构越复杂,性能的差异就会越大。

但是 v-show 相比于 v-if 的性能优势是在组件的更新阶段,如果仅仅是在初始化阶段,v-if 性能还要高于 v-show,原因是在于它仅仅会渲染一个分支,而 v-show 把两个分支都渲染了,通过 style.display 来控制对应 DOM 的显隐。

在使用 v-show 的时候,所有分支内部的组件都会渲染,对应的生命周期钩子函数都会执行,而使用 v-if 的时候,没有命中的分支内部的组件是不会渲染的,对应的生命周期钩子函数都不会执行。

因此你要搞清楚它们的原理以及差异,才能在不同的场景使用适合的指令。

列表渲染指令 v-for


<ul>
  <li v-for="(item, index) in list" :key="item.id">{{ item.name }}li>
ul>


<ul>
  <li v-for="(value, key) in obj" :key="key">{{ key }} - {{ value }}li>
ul>


<ul>
  <li v-for="(char, index) in str" :key="index">{{ index }} - {{ char }}li>
ul>


<ul>
  <li v-for="(number, index) in 5" :key="index">{{ index }} - {{ number }}li>
ul>
data() {
  return {
    list: [...],
    obj: {
      name: 'Bruce',
      age: 88,
      sex: 'unknown'
    },
    str: 'hello vue'
  }
}

key 的作用:

  • 当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
  • 为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的 key 属性。

key 的注意事项:

  • key 的值只能是字符串数字类型
  • key 的值必须具有唯一性(即:key 的值不能重复)
  • 建议把数据项 id 属性的值作为 key 的值(因为 id 属性的值具有唯一性)
  • 使用 index 的值当作 key 的值没有意义(因为 index 的值不具有唯一性)(当倒序插入数据时会出现紊乱)
  • 建议使用 v-for 指令时一定要指定 key 的值(既提升性能、又防止列表状态紊乱)

「Vue自我检验」Vue 核心基础知识点,你全了解吗?_第3张图片

(图为用index做key值时,倒序插入触发的数值紊乱)

其它内置指令

v-text

v-text 指令会覆盖元素默认值。

<p v-text="username">这段内容会被覆盖p>
data() { return { username: "Bruce" } }

v-html

v-html 存在安全问题,容易导致 XSS 攻击

<p v-html="desc">原本内容被覆盖p>
data() {
  return {
    desc: '

红色标题

'
str: '兄弟我找到你想要的资源了,快来!' } }

v-cloak

  • 本质是一个特殊属性,Vue 实例创建完毕并接管容器后,会删除 v-cloak 属性
  • 使用 CSS 配合 v-cloak 可解决网速慢时页面展示 的问题
[v-cloak] {
  display: none;
}
<h2 v-cloak>{{ username }}h2>

v-once

  • v-once 所在节点初次渲染后就成为静态内容
  • 即数据变化不会引起 v-once 所在节点内容的更新,可用于优化性能
<h2 v-once>初次的内容:{{ content }}h2>
<h2>最新的内容:{{ content }}h2>

v-pre

  • 跳过所在节点的编译过程
  • 没有使用插值语法等特殊语法的节点,可用其跳过编译过程,加快编译
<h2 v-pre>Vue 内置指令h2>
<p>用户名:{{ username }}p>

过滤器

  • 过滤器常用于文本的格式化,可用在插值表达式和 v-bind 属性绑定。
  • 过滤器只在 vue 2.xvue 1.x 中支持,vue 3.x 废弃了过滤器,官方建议使用计算属性或方法代替过滤器。

基本使用


<p>{{ message | capitalize }}p>

<div :id="rawId | formatId">div>
// 定义私有过滤器
filters: {
  capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1)
  }
}
/ 在 main.js 中定义全局过滤器
Vue.filter('capitalize', (str) => {
  return str.charAt(0).toUpperCase() + str.slice(1)
})

如果私有过滤器和全局过滤器冲突,按照就近原则调用私有过滤器。

连续调用多个过滤器

过滤器从左往右调用,前一个过滤器的结果交给下一个过滤器继续处理。

<p>{{ text | capitalize | maxLength }}p>

过滤器传参

<p>{{ message | myFilter(arg1, arg2) }}p>
// 第一个参数永远都是管道符前的值
Vue.filter('myFilter', (value, arg1, arg2) => {
  ...
})

computed 计算属性

  • 定义:使用的属性不存在,要通过已有属性计算得到
  • 原理:底层使用了 Object.defineProperty() 提供的 getter 和 setter
  • getter 何时执行:
    • 初次读取时执行一次
    • 依赖的数据发生改变时执行
  • 优点:与 methods 相比,有缓存机制,效率更高
  • 若计算属性要修改,必须声明 setter 响应修改,且 setter 中要引起依赖的数据发生改变
<span>{{ fullName }}span>  // 不用加()计算属性
// 完整写法
computed: {
  fullName: {
    get() {
      // 计算属性依赖于已有属性得到
      return this.firstName + '-' + this.lastName
    }
    set(value) {
      // setter 中要引起依赖数据的变化
      const arr = value.split('-')
      this.firstName = arr[0]
      this.lastName = arr[1]
    }
  }
}

// 简写形式
// 只有明确计算属性不需要被修改时,才能用简写形式,即没有 setter
computed: {
  fullName() {
    return this.firstName + this.lastName
  }
}

watch 侦听器

watch 侦听器允许开发者监视数据的变化,针对数据的变化做特定的操作。

侦听器可以监听普通属性和计算属性

// watch 简写形式
export default {
  data() {
    return {
      username: '',
    }
  },
  watch: {
    username(newVal, oldVal) {
      console.log('新值: ', newVal)
      console.log('旧值: ', oldVal)
    },
  },
}

默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,

需要在监听的属性里创建一个对象,并在里面设置 handler 处理函数,和 immediate 选项

使用 immediate 选项:

watch: {
  // 对象形式的侦听器
  username: {
    // handler 属性是固定写法
    handler(newVal, oldVal) {
      ...
    },
    immediate: true
  }
}

watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选项进行深度监听

export default {
  data() {
    return {
      info: { username: 'admin' },
    }
  },
  watch: {
    info: {
      handler(newVal) {
        console.log(newVal)
      },
      deep: true,
    },
  },
}

若只想监听对象里单个属性的变化,代码如下:

export default {
  data() {
    return {
      info: { username: 'admin' },
    }
  },
  watch: {
    // 记得加引号
    'info.username': {
      handler(newVal) {
        console.log(newVal)
      },
    },
  },
}

通过 Vue 实例的 $watch 监听:

const vm = new Vue({...})

vm.$watch('isHot',{
  immediate: true,
  deep: true,
  handler(newValue,oldValue) {
    console.log(newValue, oldValue)
  }
})

vm.$watch('isHot',function(newValue,oldValue) {
  console.log(newValue, oldValue)
})

动态绑定 class 和 style

通过动态绑定 class 属性和行内 style 样式,可动态操作元素样式。

动态绑定 class 类名

  • 字符串写法:类名不确定,要动态获取
  • 对象写法:要绑定多个样式,个数不确定,名字也不确定
  • 数组写法:要绑定多个样式,个数确定,名字也确定,但不确定用不用

<div class="basic" :class="mood" @click="changeMood">字符串写法div>
<div class="basic" :class="arr">数组写法div>
<div class="basic" :class="classObj">对象写法div>
export default {
  data() {
    return {
      mood: 'happy',
      arr: ['happy', 'sad'],
      classObj: {
        happy: true,  // 为true  的就使用
        sad: false,  // 为flase 不使用
      },
    }
  },
  methods: {
    changeMood() {
      this.mood = 'sad'
    },
  },
}

动态绑定 style 样式

css 属性名既可以用驼峰形式,也能用短横线形式(需要使用引号括起来)。

<div :style="{color: active, fontSize: fsize + 'px', 'background-color': bgcolor}">对象写法div>
<div :style="styleObj">对象写法div>

<div :style="[styleObj, styleObj2]">数组写法(用得少)div>
data() {
  return {
    active: 'red',
    fsize: 30,
    bgcolor: 'yellow',
    styleObj: {
      color: 'active',
      'font-size': '20px'
    },
    styleObj2: {
      backgroundColor: 'yellow'
    }
  }
}

vue 生命周期

vue 生命周期是指一个组件从创建、运行、销毁的整个过程。每个阶段对应着不同的生命周期钩子。

生命周期钩子也可理解为:Vue 在特定的时刻调用特定的函数。

除了图中 8 个钩子,还有 nextTickactivateddeactivated

关于销毁过程:

  • 销毁后借助 Vue 开发者工具看不到任何信息。
  • 销毁后自定义事件会失效,但原生 DOM 事件依然有效。
  • 一般不在 beforeDestroy 操作数据,因为即便操作数据,也不会再触发更新流程

「Vue自我检验」Vue 核心基础知识点,你全了解吗?_第4张图片

你可能感兴趣的:(前端,--,vue,框架,javascript,面试,前端)