Vue2知识点总结

214 阅读6分钟

Vue2知识点总结

Vue的基础概念

Vue是什么

Vue是个渐进式的JavaScript框架

什么是渐进式和框架

渐进式:逐渐增强,可以在项目中使用vue的一部分功能,也可以使用vue的全家桶来管理整个项目。

框架:是一套完整的解决方案。框架实现了大部分的功能,我们需要按照框架的规则写代码。比如: vue react angular ...

什么是MVVM框架

  • MVVM思想:一种软件架构模式,决定了写代码的方式。

    • M:model数据模型(ajax获取到的数据)
    • V:view视图(页面)
    • VM:ViewModel 视图模型
  • MVVM通过数据双向绑定让数据自动地双向同步 不在需要操作DOM

    • V(修改视图) -> M(数据自动同步)
    • M(修改数据) -> V(视图自动同步)

拓展:其他架构模式

  • MVC:后端的一种架构模式

    • M: model模型(业务模型)
    • V:view视图(用户页面)
    • C:controller控制器(逻辑处理)
  • MVP:是由MVC演变而来的一种架构模式

    • M: model模型(业务模型)
    • V:view视图(用户页面)
    • P:persenter控制器(逻辑处理)

脚手架的使用

全局安装脚手架/包

// npm 安装
npm i @vue/cli -g
// yarn 安装
yarn add @vue/cli global

查看版本


vue --version
vue -V

创建项目


vue create 项目名(不能使用中文,不能以数字、符号开头)

进入项目根目录


cd 目录名

运行项目


// 用哪种方式取决于创建项目时选择的是哪种安装方式
// npm 方式运行项目
npm run serve
// yarn 方式运行项目
yarn serve

style中开启less功能

  • 安装依赖

// yarn 安装依赖
yarn add less-loader@7.2.1 less -D
// npm 安装依赖
npm i less-loader@7.2.1 less -D
  • 在style标签内可以通过lang="less"开启less的功能

插值表达式(小胡子语法)

语法

{{属性}}

注意点

  1. 使用的属性必须在data中存在
  2. 不能使用if、for、switch等语句 可以使用简单的表达式(三元运算符等)
  3. 不能在标签属性中使用
  4. 不能在单标签内使用

指令

v-bind

作用:动态读取HTML中的标签元素的属性值

语法:

  • 写法一:v-bind:属性名="属性值"
  • 写法二::属性名="属性值"

v-on

作用:注册事件

一)语法:

  • 写法一:v-on:事件名="XXX"

    • v-on:事件名="少量代码"
    • v-on:事件名="methods中的函数名"
    • v-on:事件名="methods中的函数名(参数1,……)"
  • 写法二:@事件名="XXX"

    • @事件名="少量代码"
    • @事件名="methods中的函数名"
    • @事件名="methods中的函数名(参数1,……)"

二)事件对象:

  • 没有传参直接形参取值
  • 传递参数$event

三) 事件修饰符(常用的):

  • .prevent
  • .stop

四)按键修饰符(常用的):

  • .enter

v-if 和 v-show

v-if

语法:v-if="布尔值"

  • 底层: 创建和删除元素
  • 适用:要么显示要么隐藏
  • tip:惰性的, 如果不展示是默认不会创建的

v-show

语法:v-show="布尔值"

  • 底层: 控制css的display属性
  • 适用:频繁切换(tab栏)

不同点:

  • 控制手段不同

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

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

v-else 和 v-else-if

和 v-if 连着写

用法和js中基本一样(写在标签上)

v-model

vue提供的一个双向数据绑定的语法糖;

底层:@input + :value

表单元素的使用:输入框、单选,、多选、下拉

修饰符:

  • .number 将输入框的类型改为number类型
  • .trim 去除首尾空格
  • .lazy 将表单的input事件该外change事件

v-html 和 v-text

v-html --> innerHTML ————>解析标签

v-text ---> innerText————>不解析标签

v-for

作用:

  1. 遍历数组:

    
      v-for = "item in arr"
      v-for = "(item, index) in arr"
      ```
    
    
  2. 遍历对象

    
      v-for = "(value, key) in obj"
      ```
    
    
  3. 遍历数字

    
      // 可以用来遍历下拉框中是数字的情况(月份)
      v-for = "item in 12"
      ```
    

Tip:都要动态绑定key

vue中高性能对比策略

就地复用策略

  • Vue会尽可能的就地(同层级,同位置),对比虚拟dom,复用旧dom结构,进行差异化更新。
  • 就地复用的好处在于可以复用旧的dom结构,更新高效!

虚拟DOM

​ 虚拟DOM只是一层对真实DOM的映射,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上

​ 通过虚拟DOM,vue可以对这颗抽象树进行创建节点, 删除节点以及修改节点的操作, 经过diff算法得出一些需要修改的最小单位, 再更新视图,减少了dom操作,提高了性能

对比策略-diff算法

  • 策略1:先同层级根元素比较

    • 如果根元素变化,那么不考虑复用,整个dom树删除重建
    • 如果根元素不变,对比出属性的变化更新,并考虑往下递归复用。
  • 策略2:对比同级兄弟元素时,默认按照下标进行对比复用。

    • 如果指定了key,就会按照相同key的元素来进行对比复用

动态设置样式

动态设置样式类


:class="对象"
:class="{类名: true/false, ...}"
:class="数组"

动态设置行内样式


:style="对象"
:style="数组"

计算属性

什么时候用?

  • 当一个属性的结果需要依赖其它属性计算得来, 此时, 我们就可以把这个属性定义成计算属性

  • 计算属性要定义在computed选项中

  • 使用注意

    • 计算属性必须定义在computed选项中
    • 计算属性必须是一个函数, 必须是有返回值
    • 计算属性不能被当做函数调用, 要作为属性使用

它的优势

  • 计算属性有缓存:

    • 基于依赖项的值进行运算并缓存,
    • 只要依赖项的数据不变, 其它地方使用该计算属性都是直接从缓存中读取

略势:

  • 页面中有多处要使用该计算属性, 那么, 它的性能是不是很高

核心点

  • 必须写在computed选项中
  • 写法是一个函数
  • 默认情况函数必须有返回值
  • 计算属性依赖的项变化了, 会自动重新计算
  • 相比于函数, 计算属性有缓存功能

状态

  • 默认状态(简略写法):

    • 计算属性是只读不改,如果需要修改属性值,那么必须写完整写法
  • 完整写法(应用:复选框的全选反选)

    • 
      Person: {
        get() {return ...},
        set(value) { ....}
      }
      

侦听器

侦听简单类型数据

'属性名'(newVal, oldValue){
   .....
}
​
​
'对象名.属性名'(newVal, oldValue){
   ...
}

侦听复杂数据类型(必须写完整写法)

应用场景:数据存储到本地、深度侦听数组


属性名: {
   immediate: true, // 可选, 是否立即执行
deep: true, // 深度侦听
    // handler 固定函数
    handler(newValue){
       ....
    }
}

组件化

组件

  1. 独立的, 结构/行为/样式一体, 可复用的vue实例

  2. 好处

    ​ 可维护性高、可复用性高(提高开发效率)

组件化

将一个完整的页面, 拆分成一个个组件的过程 ==> 组件化

组件的基本使用


1. 创建
    .vue
2. 引入
    路径一定要对
    .vue后缀可以省略
3. 注册
    全局注册
        main.js中引入
        Vue.component('组件名', 组件对象)
        推荐
            Vue.component(大驼峰命名, 组件对象)
    局部注册
        组件内引入
        components选项中注册
4. 使用
    组件名当做标签来使用

组件的命名规范(单双标签都可以,根据项目需要)

  1. 大驼峰命名法HmButton
  2. 短横线命名法hm-button

scoped解决样式冲突

产生背景:写在组件中的样式默认是全局样式, 但是, 大多数情况希望是局部样式

如何解决?

实现原理:

​ 给组件中的所有标签都加了一个自定义属性:v-data-hash

​ 把组件内的所有选择器 ---> 属性选择器

组件通信

父传子

  1. 子组件中在props选项中定义需要接收数据的属性
  2. 以标签属性的形式传递数据

子传父

子组件发射自定义事件给父组件, 并且可以携带参数


this.$emit('自定义事件名', 参数1, ....)

父组件注册自定义事件, 在函数中接收传递过来的数据 并做业务


<Son @自定义事件名="函数名" />
methods 选项中定义函数

props验证

基础类型校验

  1. String
  2. Number
  3. Boolean
  4. Date
  5. Array
  6. Object
  7. Function
  8. ...

支持多个类型


[String, Number, Boolean, ...]

必传项


{
  type: String,
  required: true
}

默认值


// 简单数据类型
{
   type: Number,
   default: 10000
}
// 复杂数据类型
// 默认值是对象
{
   type: Object,
   default: () => {}
}
// 默认值是数组
{
    type: Array,
    default: ()=>[]
}

自定义校验(了解)


{
   validator(value){
        return  true  // 校验通过
        return   false  // 校验不通过
    }
}

v-model在组件中的使用

v-model是一个语法糖: :value + @input

使用场景:

  1. 应用于表单元素

    1. 会根据不同的表单元素, 绑定不同的值, 监听不同的事件

      1. 文本框 :value + @input
      2. 文本框.lazy :value + @change
      3. 复选和单选 :checked + @change
  2. 应用于组件

    1. v-model

      1. :value 子组件props接收 value属性

        1. @input 子组件触发自定义事件 this.$emit('input', 传递的参数)
      2. 场景:

        1. 父传子, 传单个数据
        2. 子传父, 更新数据

ref和$refs

作用:

​ ref和$refs配合, 可以帮我们获取真实的DOM和组件

语法:

  1. 给目标元素/组件, 添加ref属性
  2. 通过this.$refs.xxx获取到DOM和组件

作用场景:

​ 通过常规操作已经完成不了, 此时可以真实获取DOM或组件直接操作一般在一些三方的UI组件库使用时会经常用到

$nextTick

写法:


this.$nextTick(()=>{ .... })

为什么要用?

  • 因为vue视图是异步更新的, 如果要获取最新的dom结构, 需要等dom更新完毕, 才去获取
  • 在上一个宏任务执行完毕后, 会把收集的DOM更新一次性直接更新掉
  • 在下一个宏任务中去获取最新的DOM结构即可

动态组件


<component></component> //占位置
<component :is="组件名"></component> //is的值决定了此处展示的一个组件

使用场景非常固定:

  • 类似选项卡的场景
  • 占位的地方要可能会展示多个组件

自定义指令

自定义全局指令


Vue.directive('组件名', {
   inserted(el, binding){},
   update(el, binding){}
})

自定义局部指令


// 选项  directives
directives: {
    指令名: {
        inserted(el, binding){},
        update(el, binding){}
    }
}

前提:对DOM操作功能的封装

插槽

插槽的分类

默认插槽


<slot></slot> //作用 :占位置

具名插槽


// 子组件内
<slot name="名字">中间可以写东西,如果父组件里没有写则会展示</slot>
// 父组件内
<template v-slot:名字>内容部分</template>
// 简写
<template #名字>内容部分</template>

插槽传值-作用域插槽

  • 给插槽以添加属性的方式传值

    
    <slot name="名字" money="10000" age="18" ....></slot>
    
  • 将添加的所有属性收集到一个对象中

    
    {money: 10000, age: 18}
    
  • 使用组件的是, 给插槽提交内容是就可以用=来接收

组件生命周期

三大阶段

  1. 初始化阶段
  2. 运行阶段
  3. 销毁阶段

八个钩子函数


// 初始化阶段
beforCreate
​
created // 可以操作数据
​
beforeMount
​
mounted // 可以操作DOM// 运行阶段
beforeUpdate
updated
​
// 销毁阶段
beforeDestroy 
​
destroyed // 手动释放资源(定时器、延时器、服务器资源等)

路由

vue-router是什么?

​ vue官方提供的路由插件

​ 组件分类

​ 复用组件:components文件夹

​ 页面组件:views文件夹(vue2 版本)

如果使用vue-router?

  1. 固定配置: 5步骤

  1. 下载vue-router, Vue2项目注意版本: 3.5.3
      yarn add vue-router@3.5.3
  2. 在main.js中去引入VueRouter插件
     import VueRouter from 'vue-router'
  3. 全局注册路由插件 (生成两个组件: <router-link/> <router-view />)
     Vue.use(VueRouter)
  4. 创建路由对象
     const router = new VueRouter({
        
     })
  5. 把路由对象注入Vue实例对象 (this.router / this.route)
    new Vue({
       ...
       router
    }).$mount('#app')
  1. 自己配置 2步骤

1. 配置路由规则数组 (至关重要)
     - 在views文件夹中去创建页面组件
     - 在main.js中引入页面组件
            import Find from '@/views/Find'
            import My from '@/views/My'
            import Part from '@/views/Part'
     - 配置路由规则数组
            const router = new VueRouter({
                // 3.1 配置路由规则数组
                routes: [
                  {path: '/find', component: Find},
                  {path: '/my', component: My},
                  {path: '/part', component: Part}
                ]
            })
              
  2. 配置路由出口 
 <router-view />

安装vue-router


//  vue2 版本
yarn add vue-router@3.5.3
npm i vue-router@3.5.3

router-link 组件


// 可以用于配置导航高亮
// 内置了两个样式类
// 模糊匹配和精准匹配
    // 模糊匹配
    router-link-active
    // 精准匹配
    router-link-exact-active

路由页面传参

  1. 动态路由传参

    
    1) 路由对象
    ​
        {path: '/my/:id', component: 组件名}
    ​
    2) 页面跳转
    ​
        this.$router.push({
    ​
     path: '/my/111'
    ​
    })
    ​
    3) 对应页面组件获取
    ​
        this.$route.params.id
    ​
    
  2. query方式传参

    
    1) 路由对象
    ​
        不用改
    ​
        {path: '/my', component: 组件名}
    ​
    2) 页面跳转
    ​
        this.$router.push({
    ​
     path: '/my?id=101'
    ​
    })
    ​
    3) 对应页面组件获取
    ​
        this.$route.query.id
    ​
    

    配置路由规则数组> ```

  3. params内存方式传参(了解即可)


1) 路由对象
​
{path: '/my', component: 组件名, name: 'my'}
​
2) 页面跳转
​
this.$router.push({
​
 name: 'my',
​
 params: { car: xxx}
​
})
​
3) 对应页面组件获取
​
this.$route.params.car
​
了解就可以忘掉了
​
存储在内存中的, 刷新会丢失

两种跳转方式

  1. 声明式导航

<route-link to="/path?xxx=xxx"> xxx</route-link>
  1. 编程式导航

//  函数中
this.$router.push('/path?xxx=xxx')
​
//  模板中
$router.push('/path?xxx=xxx')
​

路由重定向


// 配置路由规则数组内第一个位置写
{path: '/', redirect: '路径'}

页面404

  1. 创建NotFound页面组件
  2. 在路由规则数组的尾部配置一个路由对象

// 配置路由规则数组内尾部写
{path: '*', component: NotFound}

路由模式


// 和routes并列
hash模式
    #/xxx
history模式
    /xx/xx
mode: 'history'
mode: 'hash'

路由嵌套


先确定二级页面组件属于哪一个一级页面组件
​
在一级路由对象中
​
    children : []
​
配置的时候, 二级的路由对象的path是不用加 /

vuex

如何使用vuex

  1. 创建仓库

  2. 在state队形中定义状态

  3. 界面使用

    
    $store.state.xxx
    ​
    // 借助辅助函数import { mapState } from 'vuex'
    ​
        computed: {
    ​
     ...mapState(['count'])
    ​
      }
    ​
    // 辅助函数底层实现
    ​
         mapState(['count', 'car'])
    ​
    // 等价于
    ​
     {
    ​
       count () {
    ​
       return this.$store.state.count
    ​
       },
    ​
       car () {
    ​
          return this.$store.state.car
    ​
       }
    ​
     }
    ​
    

vuex核心语法

state


state
    定义
        state: {
   car: '劳斯莱斯'
}
    界面使用
        方式一
            $store.state.car
        方式二
            computed选项
                computed: {
   ...mapState('car')
}

getters


定义
    getters: {
    myCar(state){
         return '我的' + state.car
    }
}
界面使用
    方式一
        $store.getters.myCar
    方式二
        computed选项
            computed: {
   ...mapGetters('myCar')
}

mutations


定义
    mutations: {
    changeCar(state){
          ....
    }
}
界面使用
    方式一
        $store.commit('changeCar', 参数)
    方式二
        methods选项
            methods: {
   ...mapMutations('changeCar')
}

actions

定义
    actions: {
    threeChangeCar(ctx){
          ....
    }
}
界面使用
    方式一
        $store.dispacth('threeChangeCar', 参数)
    方式二
        methods选项
            methods: {
   ...mapActions('threeChangeCar')
}

modules

分仓库
    namespaced: true
用法同上
    区别在于要加仓库名称