【Vue2】vue2全内容整理

文章目录

一、vue 指令

  • vue 指令就是封装的 DOM 操作,均以 v- 开头

(一)vue 指令简介

vue 指令 语法 简写 作用
v-bind v-bind:k=‘变量名’ : 动态设置 html 标签属性
v-on v-on:event=‘少量代码’
v-on:event=‘函数名’
v-on:event=‘函数名(参数1,参数2…)’
@ 注册事件
v-show v-show=‘boolean’ 控制css样式'display:none',操作频繁
v-if v-if=‘boolean’
v-if=‘条件’
动态创建或删除元素节点,隐藏时需要删除节点
v-else-if v-else-if=‘boolean’
v-else-if=‘条件’
与v-if并列
v-else v-else=‘boolean’
v-else=‘条件’
与v-if并列
v-mode:value v-model=‘变量值’ v-model 面向表单元素,实现双向数据绑定,快速获取或设置表单
v-text v-text=‘值’ innerText 不解析标签,不常用,一般用插值表达式
v-html v-html=‘值’ innerHTML 解析标签,禁止将用户输入直接作为值,易造成XSS攻击
v-for v-for=‘item in arr’
v-for=‘(item, index) in arr’
遍历数组,用于渲染结构(重要)
v-for v-for=‘(val, k) in obj’ 遍历对象,用于渲染结构(了解)
v-for v-for=‘item in 数字’ 遍历数字,用于渲染结构(了解)

(二)vue 指令补充

1、v-on

  • 获取事件对象
    • 无传参:形参接收 e
    • 有传参:$event 指代 e
  • 事件修饰符
    • 阻止默认行为:@event.prevent(e.preventDefault() )
    • 阻止冒泡:@event.stop(e.stopPropagation() )
    • 按键修饰:@event.key(@keyup.enter)
    • 原生事件:@event.native

2、v-model

(1)v-model
  • 本质:v-model:value 的缩写,通常用于表单上的双向数据绑定,也可以实现子组件到父组件的双向数据动态绑定
  • 修饰符
    • .number:以 parseFloat 转成数字类型
    • .trim:去除首位空白字符
    • .lazy:在 change (回车或失去焦点)时触发,非 input 触发
// 1、父组件
// 底层
<demo :value='money' @input=money=$event'></demo>
// 简写
<demo v-model='money'></demo>

// 2、子组件
export default{
    
    
    props:{
    
    
        value: Number // 必须叫 value
        },
    methods:{
    
    
        add(){
    
    
            this.$emit('input', this.value+1) //必须叫 input,this.value+1 是参数
        }
    }
}

(2):model
  • 本质:v-bind:model 的缩写,父组件的值传递给子组件。但是子组件改变引用类型数据,父组件的数据也会随之改变

(三)自定义指令

1、局部注册

// 组件内设置
<input type='text' v-focus>

export default{
    
    
    directives:{
    
    
        focus:{
    
     // 定义指令名时无需加 v-
            inserted(el){
    
     // 当指令所在的元素节点被插入到页面触发,DOM 解析完成
                el.focus() // element,指令所在的元素节点
            }
        }
    }
}

2、全局注册

  • Vue.directive(指令名, 指令配置对象(元素, 指令值))
// main.js 内设置
<input type='text' v-focus v-color='color'>

Vue.directive('color', {
    
    
    inserted(el, binding){
    
     // 当指令所在的元素节点被插入到页面触发,DOM 解析完成
        el.style.color = binding.value // 指令的值
    }
    update(el, binding){
    
     // 当指令绑定的值修改时触发
        el.style.color = binding.value // 指令的值
    }
})

二、虚拟 DOM 和 Diff 算法

(一)就地复用

  • 定义:vue 尽可能就地(同层级、同位置)对比虚拟 dom,复用旧 dom 结构,进行差异化更新
  • 优点:复用旧 dom 结构,高效更新

(二)虚拟 DOM

  • 本质:保存节点信息,描述真实 DOM 的 JS 对象
  • 作用:提升对比性能

(三)Diff 算法

  • 同级根元素比较
    • 根元素变化:不考虑复用,整个DOM 树删除重建
    • 根元素不变:对比属性变化,向下递归复用
  • 同级兄弟元素比较
    • 不设 key:默认按照下标进行比较
    • 设置 key:优先相同 key 的元素对比复用
      • key 特性:必须为字符串数字,且保证唯一性(一般为 id)
      • key 作用:提高虚拟 DOM 的对比复用性

三、计算属性

(一)认识

  • 定义:一个特殊属性,值依赖于一些数据动态计算
  • 注意
    • 必须定义在 computed 节点中
    • 必须是 function,必有返回值
    • 不能作为方法调用,作为属性使用
  • 特点
    • 计算后立即缓存,下次直接读取
    • 依赖项改变,函数重新执行并重新缓存
    • 多次使用计算属性,性能极高

(二)完整写法

  • 计算属性默认情况下,只能获取不能修改
  • 给计算属性赋值需要完整写法
computed:{
    
    
        full:{
    
    
            get(){
    
    },
            set(val){
    
    }
    }
}

四、监视属性

watch: {
    
    
    // 1、监视简单数据类型
    'money' (oldVal, newVal) {
    
    
      console.log(`银行卡余额为${
      
      newVal},原${
      
      oldVal}`)
    },
    'obj.age' (oldVal, newVal) {
    
     // 监视复杂数据的属性必须用括号包裹
      console.log(`长大了,今年${
      
      newVal}岁,之前${
      
      oldVal}`)
    },

    // 2、监视复杂数据类型
    person: {
    
    
      immediate: true, // 立即执行,一进页面立刻执行
      deep: true, // 复杂数据深度监视
      handler (newVal) {
    
     // handler 执行函数,新旧值一致
        console.log(newVal)
      }
    }
  }

五、组件

(一)Vue 组件

  • 组件:可复用的 Vue 实例,封装标签样式JS 代码
    • 目的:复用、拆解
    • 优点:各自独立,便于复用,可维护性高
  • 组件化开发:封装思想,把页面上重复部分封装为组件,便于项目开发和维护

1、局部注册

  • 创建:组件中创建 .vue(标签/样式/JS)
  • 引入:组件中引入
  • 注册:组件中注册
  • 标签:组件中使用

2、全局注册

  • 创建:组件中创建 .vue(标签/样式/JS)
  • 引入:main.js 中引入
  • 注册:main.js 中注册
  • 标签:组件中使用

(二)组件通信

  • 各组件数据独立,组件间数据无法互相直接访问,组件通信实现跨组件访问数据

1、父传子

  • 父组件给子组件添加标签属性传值
  • 子组件内部通过 props 接收只读数据
// 父组件
<MyHome>
    v-for='item in list'
    :key='item.id'
    :title='item.proname'
    :price='item.proprice'
    :info='item.desc'
    :pid='item.id'
</MyHome>

// 子组件
props:['title','price','info','pid']
  • props 校验:为了提高子组件被使用时的稳定性,验证传递数据是否符合要求
props: {
    
    
  // 1、基础类型检查 Number String Boolean Object Array Function...
  data:Array,
  money:Number,

  // 2、多个可能类型 [String, Number,...]
  params:[String, Number,Boolean],

  // 3、必填项(要求用户必须填写,否则报错)
  age:{
    
    
      type:Number,
      required:true
  },

  // 4、默认值(用户选填,不填则使用默认值)
  title:{
    
    
      type:String,
      default:'大标题'
  }

}
  • 单向数据流:从父到子的单向数据流动,通过子传父发起申请解决

2、子传父

  • 子组件通过 this.$emit('自定义event',参数,this.id) 触发事件的同时传参
  • 父组件给子组件注册对应的自定义事件 <Son @自定义event='fn(参数,id)'></Son>

六、ref 属性和 $nextTick

(一)ref 和 $refs

  • 作用:获取 dom 元素或组件实例
  • 区别
    • document.querySelector:查找整个 document,不区分组件,作用范围广
    • ref 和 $refs:查找当前整个组件,有查找范围
// 1、目标元素添加 ref 属性
<h1 ref='myH1'>ref获取原生DOM</h1>
<MySon ref='son'>ref获取组件实例</MySon>

// 2、通过 this.$refs.xxx 获取元素/组件
console.log(this.$refs.myH1)
console.log(this.$refs.son.属性/方法)

(二)$nextTick

  • 背景:Vue 异步更新 DOM,即当前主线程代码执行完毕后一起更新,不能在修改数据之后立即更新 DOM
  • 解决原理:宏任务执行完成后优先查看执行微任务,浏览器完成更新渲染,然后执行下一个宏任务

1、setTimeout()

setTimeout(() => {
    
    
    // setTimeout()为宏任务,执行此代码前浏览器完成更新渲染
}, 0)

2、$nextTick()

this.$nextTick(() => {
    
    
    // DOM 更新完毕后立即执行此代码
})

七、动态组件

  • 定义:可以改变的组件,解决多组件同一位置切换显示的需求
  • 语法
    • component组件(显示位置) + is属性(具体组件)
    • 修改 is属性绑定值,进行组件切换
<component :is='要显示的组件'/>
  • 步骤
    • 准备被切换的组件并引入注册
    • 准备变量 comName 来承载要显示的组件名
    • 设置挂载点<component>,js 属性设置要显示的组件(component + is)
    • 点击事件-修改 comName 变量里的组件名(修改 is 的值)

八、插槽

  • props:用于传值,解决简单场景组件定制
  • 插槽:用于传结构,解决自定义场景组件定制
  • 基本语法
    • 组件内占位:<slot></slot>
    • 使用组件:写入实际代码结构
    • 后备内容:slot 标签内放置内容,外部未传结构时默认显示

(一)具名插槽

  • 默认插槽:未定义名字,默认名字为 default
  • 具名插槽:通过 name 自定义名字,实现定向分发
// 1、组件内多处 slot 需要外部传入标签,通过 name 属性进行定制
<slot name='first'></slot>
<slot name='second'></slot>


// 2、template 配合 v-slot:名字/#名字 分发标签
<template v-slot:first>
    <p>一个slot结构</p>
</template>

<template #second> // v-slot: 简写为 #
    <p>另一个slot结构</p>
</template>

(二)作用域插槽

  • 插槽通过添加属性的方式传值携带参数
  • 将添加的所有属性收集到一个对象中
  • 组件使用者通过=接收,仅在当前 template 范围内使用
<slot name='first' title='我是标题' desc='我是描述'></slot>
<slot name='second' :change='change' :edit='edit' money='100'></slot>


<template #first='obj'>
    <p>{
    
    {
    
    obj.title}}</p>
    <p>{
    
    {
    
    obj.desc}}</p>
</template>

<template #second='{change, edit, money}'>  // 结构数据
    <button>{
    
    {
    
    change}}</button>
    <button>{
    
    {
    
    edit}}</button>
    <p>{
    
    {
    
    money}}</p>
</template>

九、生命周期

  • 生命周期函数:Vue 的内置函数,伴随组件生命周期自动按序执行
  • 初始化阶段:结合数据,结合模板,渲染视图
    • beforeCreate():data 数据未完成初始化,vue 实例上还未绑定数据
    • created()data 数据完成初始化,vue 实例上成功绑定数据
  • 数据更新阶段:数据变化,视图更新
    • beforeMount():页面结构未完成解析渲染,无法获取 DOM
    • mounted()页面结构完成解析渲染,可以获取 DOM
    • beforeUpdate():数据变化后由于 vue 异步更新 DOM,DOM 还未更新
    • updated():数据变化后 DOM 完成更新
  • 组件销毁阶段
    • beforeDestory():实例销毁、资源释放前(定时器、延时器、服务器资源)
    • destoryed():实例销毁、资源释放后(定时器、延时器、服务器资源)

十、路由

  • 定义:路径和组件的映射关系

(一)vue-router

  • 定义:vue 官方路由插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8WjLauG-1669287358087)(./vue-router.png)]

1、基本使用

  • 下包:下载 vue-router 模块到当前工程,vue2 使用 @3版本
  • 引入:main.js 中引入 VueRouter
  • 注册:添加到 Vue.use(),插件内部初始化,注册全局组件、指令
  • 实例:创建路由组件
  • 挂载:将路由对象注入到 new Vue 实例
  • 规则:路由实例中配置路径和组件的对应
  • 出口:App.vue 中 router-view 渲染位置

2、操作技巧

  • @ 指代 src 目录,可直接从 src 出发找文件,提高可维护性
  • 封装抽离:将路由模块抽离到 @/router/index.js,使得模块拆分,利于维护

(二)配置页面

1、路由重定向

  • 定义:匹配 path 后,redirect 强制跳转 path 路径
const routes = [
    {
    
    
        path:'/',
        redirect:'/home'
    }
]

2、配置页面404

  • 定义:找不到路径匹配时,component 提供页面错误提示
const routes = [
    ...,
    {
    
     // 放在路由最后
        path:'*', // 匹配任意路径,前面不匹配命中最后规则
        component:NotFound
    }
]

3、路由模式

  • hash 路由
const router = new VueRouter({
    
    
    mode:'hash', // 默认
    routes
})
  • history 路由(上线需服务器端支持)
const router = new VueRouter({
    
    
    mode:'history',
    routes
})

(三)跳转方式

1、声明式导航

(1)导航链接
  • 组件 router-link 代替 a 标签,自带激活类名,可以做高亮
    • 模糊匹配:router-link-active
    • 精准匹配:router-link-exact-active
<router-link to='/home'>首页</router-link>
<router-link to='/my'>我的</router-link>
<router-link to='/part'>朋友</router-link>
(2)跳转传参
  • 目标:跳转路由时给对应组件传值
  • 查询参数
    • 传参:router-link 的 to=‘/path?k=val&k=val’
    • 接收:$route.query.k
  • 动态路由传参
    • 路由对象配置 path:‘/path/:k/:k’
    • 传参:router-link 的 to=‘/path/val&val’
    • 接收:$route.params.k
(3)跳转缓存
  • 背景:切换路由时默认销毁/重建页面,用户切换页面时体检不佳
  • 方案:使用<keep-alive>包裹 router-link 进行缓存
  • 影响:生成两个钩子
    • activated:缓存组件被激活
    • deactivated:缓存组件被隐藏

2、编程式导航

(1)基本跳转
  • JS 代码 path 跳转
this.$router.push({
    
    
    path:'路由路径', // router/index.js 内定义
    '路由路径', // 简写形式
})
  • JS 代码 name 跳转
this.$router.push({
    
    
    name:'路由名', // router/index.js 内定义
})
  • JS 代码 go 跳转
this.$router.go(n) // n 正负数代表前进或后退步数
  • 注意
    • router:整个大的路由实例,可用于路由跳转,等同 this.$router
    • route:路由规则相关,等同 this.$route
(2)跳转传参
  • path 仅支持 query 传参,忽略 params
this.$router.push({
    
    
    path:'路由名', // path 带参数
    query:{
    
    
        'k':val,
        'k':val
    }
})
this.$router.push({
    
    '路由名?k=val&k=val'}) // path 带参数简写
this.$router.push({
    
    
    path:'路由名',  // path 带参数
    query:{
    
    
        'k':val
    },
    params:{
    
     // params 即使存在也被忽略
        'k':val
    }
})
  • name 支持 query 和 params 传参,但 params 传参刷新会消失
this.$router.push({
    
    
    path:'路由名', // path 带参数
    query:{
    
     // 拼接在地址栏,刷新不会丢失
        'k':val,
        'k':val
    }
})
this.$router.push({
    
    
    name:'路由名',  // path 带参数
    params:{
    
     // 地址栏不显示,基于内存刷新会消失,需要配合本地存储进行持久化
        'k':val,
        'k':val,
    }
})

(四)页面路由传参

1、动态路由传参(优雅)

  • 配置路由:路径携带参数
{
    
    path:'/user/:k', component:xxx}
  • 跳转:仅路径(含参数)
<router-link to='/user/val'></router-link> // 标签方式跳转
this.$router.push('/user/val') 			   // JS 方式跳转,简洁版
this.$router.push({
    
     					   // JS 方式跳转,复杂版
	path:'/user/val'
}) 	
  • 获取参数
this.$route.params.k

2、query 传参(多参数)

  • 路由:无需特殊配置
{
    
    path:'/user', component:xxx} // 忽略
  • 跳转:携带查询参数
<router-link to='/user/?k=val'></router-link> // 标签方式跳转
this.$router.push('/user/?k=val') 			  // JS 方式跳转,简洁版
this.$router.push({
    
     					      // JS 方式跳转,复杂版
	path:'/user',
	query:{
    
    k:val},
	params:{
    
    k:val} // params 被忽略
}) 	
  • 参数获取
this.$route.query.id

3、params 传参(了解)

  • 路由:额外配置 name
{
    
    path:'/user', name:'user', component:xxx} // 配置 name
  • 跳转:通过 name 跳转
this.$router.push({
    
    
    name:'user',
    query:{
    
    k:val}, 
    params:{
    
    k:val}
})
  • 参数获取:基于内存传参,刷新丢失
this.$route.params.k // 刷新会丢失,不显示在地址栏,基于内存

十一、Vuex

(一)概述

  • vuex:vue 的状态(数据)管理工具,集中管理 vue 中通用的数据
  • 作用:解决多组件状态共享问题
  • 优点
    • 响应式变化
    • 操作更简洁

(二)基本使用

1、创建仓库

  • 安装
yarn add vuex@3.x.x
  • 新建 store/index.js 存放 vuex
  • 创建仓库 store/index.js
// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex)

// 创建仓库 store,基于Vuex里的Store构造函数创建仓库实例
const store = new Vuex.Store()

// 导出仓库
export default store
  • 在 main.js 中导入挂载到 Vue 实例上
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
    
    
  render: h => h(App),
  store
}).$mount('#app')

此刻起, 就成功创建了一个 空仓库!!

2、state 状态

(1)基本使用
  • 定义:存放数据的仓库
  • 特点:State 提供唯一公共数据源,所有共享数据都统一放到 Store 中的 State 存储
    • data:组件内数据
    • state:vue 项目公共数据
  • 提供数据
// 创建仓库 store
const store = new Vuex.Store({
    
    
  state: {
    
    
    count: 101
  }
})
(2)原生语法- 插值表达式
  • 获取数据:this.$store.state.属性
<h1>state 的数据 - {
    
    {
    
     $store.state.count }}</h1> // 原始复杂写法
  • 将 state 属性定义在计算属性中,简化插值语法
<h1>state 的数据 - {
    
    {
    
     count }}</h1> // 简化后的插值语法

computed: {
    
    
  count () {
    
     // 可以使用 mapState 辅助函数简化
    return this.$store.state.count
  }
}
(3)辅助函数 - mapState
  • 获取数据:mapState 辅助函数将 store 中的数据映射到组件的计算属性
  • 导入 mapState
import {
    
     mapState } from 'vuex'

<h1>state 的数据 - {
    
    {
    
     count }}</h1> // 简化后的插值语法

computed: {
    
    
  ...mapState(['count']) // 利用展开运算符将导出的状态映射给计算属性,
                         // 防止 mapState 辅助函数独占计算属性
}

3、mutations

(1)基本使用
  • 定义:存放操作数据的方法
  • 背景:vuex 遵循单向数据流,state 数据修改只能通过 mutations,且 mutations 必须是同步的
  • 提供方法
// 提供 mutations 函数
const store  = new Vuex.Store({
    
    
  state: {
    
    
    count: 0
  },
  // 定义mutations
  mutations: {
    
    
    // 第一个参数是当前store的state属性(固定)
    addOne (state {
    
     
      state.count ++ // 通过形参 state 拿到仓库 store 数据
    }
  },
})

// 调用方法
this.$store.commit('addOne')
(2)携带参数
  • 提供 mutations 方法
const store  = new Vuex.Store({
    
    
  state: {
    
    
    count: 0
  },
  // 定义mutations
  mutations: {
    
    
    // 第一个参数是当前store的state属性(固定)
    addOne (state {
    
     
      state.count ++ // 通过形参 state 拿到仓库 store 数据
    }
    // 第二个参数payload额外参数,调用mutaiions的时候传参(一次提交仅限携带一个参数,但参数类型不限,支持数组、对象等)
    addNth (state, payload) {
    
     
      state.count += payload
    }
  },
})
  • 注册事件
<input type="text" :value="count" @input="fn">
  • 调用方法
fn(e){
    this.$store.commit('addNth', +e.target.value) // 请求参数
}
(3)辅助函数 - mapMutations
  • 原代码
methods: {
    
          
      subOne () {
    
    
          this.$store.commit('subOne')
      },
      subNth (n) {
    
    
          this.$store.commit('subOne', n) // commit(方法名, 载荷参数)
      }
 }
  • 导入 mapMutations
import  {
    
     mapMutations } from 'vuex'

methods: {
    
    
    ...mapMutations(['subOne', 'subNth'])
}
  • 调用
<button @click="subOne">+1</button> // 无参数
<button @click="subNth(n)">+1</button> // 携带参数

4、actions

(1)基本使用
  • 定义:存放异步操作的方法,不能直接修改数据
actions: {
    
    
  setAsyncCount (context, num) {
    
    
    // 一秒后, 给一个数, 去修改 num
    setTimeout(() => {
    
    
      context.commit('inputCount', num)
    }, 1000)
  }
},
(2)原始调用
  • $store (支持传参)
setAsyncCount () {
    
    
  this.$store.dispatch('setAsyncCount', 200)
}
(3)辅助函数 - mapActions
import {
    
     mapActions } from 'vuex'

<button @click="setAsyncCount(200)">+异步</button>

methods: {
    
    
    ...mapActions(['setAsyncCount'])
}

5、getters

(1)基本使用
  • 定义:存放基于 state 的一些计算属性
state: {
    
    
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
},
getters: {
    
    
  // getters函数的第一个参数是 state
  // 必须要有返回值
    filterList:  state =>  state.list.filter(item => item > 5)
}
(2)原始方式 - $store
<div>{
   
   { $store.getters.filterList }}</div>
(3)辅助函数 - mapGetters
 <div>{
    
    {
    
     filterList }}</div>

computed: {
    
    
    ...mapGetters(['filterList'])
}

6、模块 modules(重要)

  • 定义:为解决 store 对象臃肿问题,建立 @/store/module/xx.js 进行 Vuex 的模块化
(1)模块定义
  • 准备 state,定义两个模块 user 和 setting
  • user 中管理用户的信息状态 userInfo modules/user.js
const state = {
    
    
  userInfo: {
    
    
    name: 'zs',
    age: 18
  }
}
const mutations = {
    
    }
const actions = {
    
    }
const getters = {
    
    }

export default {
    
    
  state,
  mutations,
  actions,
  getters
}
  • setting 中管理项目应用的名称 title, desc modules/setting.js
const state = {
    
    
  title: '这是大标题',
  desc: '描述真呀真不错'
}
const mutations = {
    
    }
const actions = {
    
    }
const getters = {
    
    }

export default {
    
    
  state,
  mutations,
  actions,
  getters
}
  • 使用模块中的数据
    • 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.title
    • 可以通过 mapState 映射
(2)命名空间 namespaced
  • 默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间,配置 namespaced 保证内部模块的高封闭性
const state = {
    
    
  userInfo: {
    
    
    name: 'zs',
    age: 18
  },
  myMsg: '我的数据'
}
const mutations = {
    
    
  updateMsg (state, msg) {
    
    
    state.myMsg = msg
  }
}
const actions = {
    
    }
const getters = {
    
    }

export default {
    
    
  namespaced: true, // 配置命名空间
  state,
  mutations,
  actions,
  getters
}
  • 提交模块中的 mutation
全局: this.$store.commit('mutation函数名', 参数)
模块: this.$store.commit('模块名/mutation函数名', 参数)
  • namespaced: true 后, 可以加上模块名添加映射, 找对应模块的 state/mutations/actions/getters
computed: {
    
    
  // 全局的
  ...mapState(['count']),
  // 模块中的
  ...mapState('user', ['myMsg']),
},
methods: {
    
    
  // 全局的
  ...mapMutations(['addCount'])
  // 模块中的
  ...mapMutations('user', ['updateMsg'])
}

7、语法汇总

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_64210950/article/details/128024539