Vue2高级篇

Vue高级

Vue生命周期

生命周期又称为生命周期回调函数、生命周期函数、生命周期钩子, 是Vue在运行过程中的关键时刻帮我们调用的一些指函数, 生命周期函数名字不可修改, 其中的this指向的是vm或组件实例对象.

常用的生命周期钩子:

  • mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  • beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等收尾工作

在这里插入图片描述

关于销毁Vue实例

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

组件

组件的定义——实现应用中局部功能代码和资源集合, 使用组件化可以复用代码, 简化项目编码, 提高运行效率

  • 模块化: 当应用中的js都以模块来编写的, 那这个应用就是一个模块化的应用
  • 组件化: 当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用

在这里插入图片描述

通过Vue.extend(options)可以创建一个组件, 其中options和new Vue(options)时传入的options几乎一样, 但也有点区别:

  • el不能写, 最后所有的组件都要经过一个vm的管理, 由vm中的el决定服务于那个容器
  • data必须写成函数, 因为组件通常都是复用的, 数据存在引用关系

注册组件的方式分为:

  1. 局部注册: 通过new Vue时传入components选项
  2. 全局注册: 通过Vue.component('组件名', 组件)
<div id="app"><!-- 3. 使用组件 --><school></school>
</div>
<script>// 1. 声明一个组件 可以不写Vue.extend, 直接写对象const school = Vue.extend({template: `<div><h1>{{ name }}</h1><h1>{{ address }}</h1></div>`,data() {return {name: 'putian',address: 'fujian'}}})new Vue({el: '#app',// 2. 注册组件components: {school}})
</script>

使用Vue组件时, 大驼峰式()的组件或单标签的写法都需要Vue脚手架支持.

Vue组件本质上是一个名为VueComponent的构造函数, 通过Vue.extend()生成的, 不同类型的组件对应的VueComponent构造函数不同(虽然名字都是同一个). 当我们使用组件时, 即在模板中声明<school></school>后, Vue解析时会帮我们创建school组件的实例对象. 也就是new VueComponent(options)

关于this指向问题

  • 组件配置中: data函数、methods中的函数、watch中的函数、computed中的函数都是VueComponent实例对象
  • new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数都是Vue实例对象

VueComponent.prototype._proto_ === Vue.prototype

有个如上的关系, 才能让组件实例对象可以访问到Vue原型上的属性、方法, 如图:

在这里插入图片描述

组件标识ref

ref被用来给元素或者子组件注册引用信息(id的替代者). 当ref应用在html标签上时, 获取的时真实DOM元素, 当应用在组件标签上时则是组件实例对象.

使用方式:

  • 声明标识
<h1 ref="xxx">...</h1>
<School ref=""></School>
  • 获取组件
this.$refs.xxx //xxx为ref的值

例如:

<School ref="school"></School>export default {name: 'App',components: {School},methods: {showInfoApp() {console.log(this.$refs.school);}}
}
组件通信props

功能: 让组件接收外部传过来的数据(可以是函数)

语法: 使用组件时:

​ 组件定义时:

写法一: 简单接收声明接收——数组

new Vue({props: ['name', 'key2', 'key3']
})

写法二: 接收的同时对数据进行类型限制 简单对象

new Vue({props: {name: String,age: Number}
})

写法三: 接收的同时对数据进行类型限制 复杂对象, 默认值指定+必要性限制+类型限制

new Vue({props: {name: {type: String,// required: false,default: 'wang'}}
})

props是只读的, Vue会监测对props的修改, 如果进行了修改, 就会发出警告. 若业务需求确实需要修改, 那么需要复制props的内容到data中一份, 然后去修改data中的数据即可

混入mixin

功能: 可以把多个组件公用的配置提取成一个混入对象

  • 定义混合
// 定义一个混入js文件并导出对象
export const mixin = {methods: {showInfo() {alert(this.name)}}
}
  • 使用混入
// 1.导入混入
import {mixin} from "@/mixin";
// 2.使用混入(局部混入)
new Vue({mixins: ['mixin']
})
// 全局混入
Vue.mixin(xxx)

混入即将内容与组件内的内容合并, 当data产生冲突时, 会以组件内部声明的为主. vue的声明周期函数也可以使用混入, 这时会先调用混入的生命周期函数, 然后才调用组件内部的.

插件plugins

插件可以增强Vue, 其本质是包含install方法的一个对象, install的第一个参数是Vue, 第二个以后的参数是插件使用者传递的自定义参数.

  • 定义插件
对象.install = function(Vue, options) {// 1. 添加全局过滤器Vue.filter(...)// 2. 添加全局指令           Vue.directive(...)// 3. 配置全局混入(合)Vue.mixin(...)// 4. 添加实例方法Vue.prototype.$myMethod = function() {...}Vue.prototype.$myProperty = xxx
}
  • 使用插件
import plugins from ''
Vue.use('plugins', 'xx', 'xxx')
组件化编码流程
  1. 拆分静态组件: 组件要按照功能点拆分, 命名不能跟html元素冲突
  2. 实现动态组件: 需要考虑数据的存放位置, 数据是一个组件在用, 还是多个组件在用
    • 一个组件在用: 放在组件自身即可
    • 多个组件共用: 放在组件共同的父组件上(状态提升)
  3. 实现交互: 从绑定事件开始

案例: 组件化编码TODO

当数据在多个组件共用时, 会涉及组件的通信问题, props配置项适用于父子组件之间的通信, 这个通信是双向的, 既可以父传子, 也可以子向父组件传递信息(父组件传递函数给子组件)

使用v-model时, v-model绑定的值不能时props传递过来的值, 因为props是不可以修改的, 它是只读的

组件的自定义事件

组件的自定义事件是一种组件之间通信的方式, 适用于子组件向父组件传递信息.

使用场景: A是父组件, B时子组件, B想给A穿数据, 那么就要在A中给B绑定自定义事件(事件的回调函数在A中)

  1. 绑定自定义事件的两种方式(在使用到该组件的组件上绑定):
<!-- 方式一 -->
<Demo @testEvent='func'/>
<Demo v-on:testEvent='func'/>  
// 方式二
<Demo ref='demo'/>mounted() {this.$refs.demo.$on('testEvent', this.func)
}

若只想让自定义事件只能触发一次, 可以使用once修饰符, 或者方式二中$on换成$once

  1. 触发自定义事件(在子组件中触发):
this.$emit('eventName', 参数)
  1. 解绑自定义事件:
this.$off('eventName') // 解绑一个事件
this.$off(['eventName1', 'eventName2']) // 解绑多个事件
this.$off() // 解绑所有事件

组件上也可以绑定原生DOM事件, 需要使用native修饰符

通过this.$ref.xxx.$on('eventName', func)绑定自定义事件时, 回调要配置在methods中, 要么使用箭头函数, 否则this指向会有问题

全局事件总线

全局事件总线是一种组件之间通信的方式, 适用于任意组件之间通信

  1. 安装全局事件总线
new Vue({// ...beforeCreate() {Vue.prototype.$bus = this // 安装全局实现总线, ¥bus就是当前正在创建的vm}
})
  1. 使用事件总线
  • 接收数据: A组件想要接收数据, 则在A组件中给$bus绑定自定义事件, 事件的回调留在A组件自身
methods: {// 声明回调demo(param) {// ..}
}
mounted() {this.$bus.$on('xxx', this.demo)
}
  • 提供数据
this.$bus.$emit('xxxx', 数据)

在beforeDestroy钩子中, 记得使用*$off*去解绑当前组件所用到的事件

消息订阅与发布

消息订阅发布也是一种组件间通信的方式, 适用于任意间组件的通信

  1. 安装pubsub库:
npm i pubsub-js
  1. 引入模块
import pubsub from 'pubsub-js'
  1. 订阅消息: A组件向接收数据, 则在A组件中订阅消息, 订阅的回调留在A组件自身
methods: {// 第一个参数是消息名称, 第二个开始才是真正的参数demo(msgName, data) {//...}
}
mounted() {this.pid = pubsub.subscribe('xxx', this.demo) // 订阅消息
}

发布订阅消息并不是Vue中的内容, 因此直接写普通函数时, this并不是vm实例对象, 此时可以写成箭头函数, 或者在methods中声明的函数

  1. 发布消息
pubsub.publish('xxx', 数据)
  1. 取消订阅
beforeDestroy: {pubSub.unsubscribe(pid)
}
$nextTick

语法: this.$nextTick(回调函数)

作用: 在下一次DOM更新结束后执行其指定的回调

当数据改变后, 要基于更新后的新DOM进行某些操作时, 要在nextTick所指定的回调函数中执行

插槽

作用: 让父组件可以向子组件指定位置插入html结构, 也是一种组件间通信的方式, 适用于父组件 => 子组件

  1. 默认插槽
<!-- parent -->
<Category><div>html...</div>
</Category>
<!-- child -->
<template><div><!-- define slot --><slot>default content</slot></div>
</template>
  1. 具名插槽
<!-- parent -->
<Category><template slot='center'><div>html tag</div></template><template v-slot:footer><div>html tags</div></template>
</Category>
<!-- child -->
<template><div><slot name='center'>defaut content</slot><slot name='footer'>defaut content</slot></div>
</template>
  1. 作用域插槽
<!-- parent -->
<Category><!-- receive data here --><template scope='scopeData'><!-- ul --><ul><li v-for='g in scopeData.games' :key='g'>{{ g }}</li></ul></template>
</Category><Category><template scope='scopeData'><!-- ol --><ol><li v-for='g in scopeData.games' :key='g'>{{ g }}</li></ol></template>
</Category>
<!-- child -->
<template><div><!-- scope slot --><slot :games="games"></slot></div>
</template><script>export deafault{name: 'Category',data() {// 数据在子组件中, 结构由使用者决定return {games: ['game1', 'game2']}}}
</script>

数据在组件自身, 但根据数据生成的结构需要组件的使用者来决定时才使用作用域插槽

Vuex

Vuex时专门在Vue中实现集中式状态(数据)管理的一个Vue插件, 对vue应用中多个组件的共享状态进行集中式的管理(读/写), 也是一种组件间通信的方式, 且适用于任意组件间的通信

在这里插入图片描述

  1. 多组件共享数据——全局事件总线

当涉及组件太多, 全局事件总线实现共享数据就很麻烦了.

在这里插入图片描述

  1. 多组件共享数据——vuex实现
  • 多个组件依赖于同一状态
  • 来自不同组件的行为需要变更同一状态

在这里插入图片描述

vuex基本使用
  1. 创建配置文件: src/store/index.js
import Vue from "视频笔记/前端/Vue/VueJunior"
import Vuex from "vuex"// 应用vuex插件, 无法在App.vue中使用Vuex, 模块里的代码会先被执行, 然后才Vue.use
Vue.use(Vuex)// 用于响应组件中的动作(业务逻辑)
const actions = {}
// 用于操作数据(方法名通常大写)
const mutations = {}
const state = {}export default new Vuex.Store({actions, mutations, state
})
  1. 使用store
import store from "@/store";export default {name: 'App',components: {HelloWorld,store}
}
  1. actions中的参数
// 第一个参数为上下文对象, 包含了dispach和commit等对象, 第二个为值
oddAdd(context, value) {if (context.state.sum % 2) context.commit('ADD', value)
}
  1. mutations中的参数
// 真正操作state的地方, 第一个参数为state对象
ADD(state, value) {state.sum += value
}

若没有网络请求或其他业务逻辑, 组件中也可以越过actions, 即不写dispatch 直接编写commit

getters配置项

当state中的数据需要加工后再使用时(逻辑复杂, 并且需要复用时), 可以使用getters加工.

  1. store.js中追加getters配置
const getters = {// 第一个参数就是数据源bigSum(state) {return // ...}
}
  1. 组件中读取数据
$store.getters.bigSum

可以将state和getters类比为vue中的data和computed之间的关系

Vuex的四个map方法的使用
  1. mapState方法: 用于映射state中的数据为计算属性
import { mapState } from Vuexcomputed: {// 借助mapState生成计算属性: 对象写法...mapState({ add:'add'})// 数组写法...mapState(['add'])
}
  1. mapGetters方法: 映射getters中的数据为计算属性
computed: {...mapGetters({bigSum:'bigSum'})// 数组写法...mapGetters(['bigSum'])
}
  1. mapActions方法: 用于在组件中生成与actions 对话的方法, 即包含$store.dispatch(xxx)的函数
methods: {...mapActions({ incrementOdd: 'incrementOdd', incrementWait:'incrementWait'})// 数组写法...mapActions(['incrementOdd', 'incrementWait'])
}
  1. mapMutations方法: 用于生成在组件中与mutations对话的方法, 即包含$store.commit(xxx)的函数
methods: {...mapMutations({increment: 'INCREMENT', decrement:'DECREMENT'})// 数组写法...mapMutations('INCREMENT', 'DECREMENT')
}

mapActionsmapMutations使用时, 若需要传递参数, 在模板中绑定事件时需要传递好参数, 否则参数时事件对象

模块化与命名空间

可以将一类功能的配置项放到一个对象中, 并用命名空间将其标识

const countAbout = {namespaced: true,state: { x: 1},mutations: {...},actions: {...},getters: {...}
}const personAbout = {namespaced: true,state: { x: 1},mutations: {...},actions: {...},getters: {...}       
}new Vuex.Store({modules: {countAbout,personAbout       }            
})            
  1. 开启命名空间后, 组件中读取state数据:
// 方式一:
this.$store.state.personAbout.x
// 方式二:
...mapState('namespace', ['x'])
  1. 读取getters数据
// 方式一:
this.$store.getters['personAbout/firstPersonName']
// 方式二:
...mapGetters('countAbout', ['bigSum'])
  1. 组件中调用dispatch
// 方式一
this.$store.dispatch('personAbout/xxx')
...mapActions('countAbout', ['xxx'])
  1. 组件中调用commit
// 方式一
this.$store.commit('personAbout/xxx', value)
...mapMutations('countAbout', ['xxx'])

路由

一个路由(route)就是一组映射关系, 多个路由需要路由器(router)进行管理

路由的基本使用
  1. 安装vue-router, 命令: npm i vue-router

  2. 应用插件: Vue.use(VueRouter)

  3. 配置路由

import VueRouter from 'vue-router'export default new VueRouter({routes: [{name: 'xxx', // 路由命名(使用路由时方便编码)path: '/about',component: About,children: [{path: 'news', // 此处路由不需要再写’/‘component: News}]},// ...]
})
  1. 实现切换路由(active-class可配置高亮样式)
<router-link active-class='active' to='/about'>About</router-link>

路由跳转时, to属性还能写成对象形式, 如果路由有name属性, 可以不写路径, 通过name也能跳转

  1. 指定展示位置
<router-view></router-view>

几个注意点

  • 路由组件通常放在pages文件夹, 一般组件通常存放在components文件夹
  • 通过切换, “隐藏”了的路由组件, 默认是被销毁的, 需要的时候会重新挂载
  • 每个组件都有自己的$route属性, 里面存储着自己的路由信息
  • 整个应用只有一个router, 可以通过组件的$router属性获取到
路由传参
通过query传参
  1. 传递参数
<!-- 方式一:字符串写法 -->
<router-link :to='/home/message/detail?id=xxx&title=xxx'></router-link><!-- 方式二:对象写法 -->
<router-link :to='{path: `/home/message/detail`,query: {id: xxx,title: xxx}}'
  1. 接收参数
$route.query.xxx
通过params传参
  1. 配置路由, 声明接收params参数
new VueRouter({path: '/home',component: Home,children: [{path: 'news/:id/:title', //使用占位符声明接收params参数component: News}]
})
  1. 传递参数
<router-link :to='/home/message/detail/xxx/xxx'></router-link>

路由携带params参数时, 如果使用to的对象写法, 则不能使用path配置项, 必须使用name配置!

路由的props配置

通过配置props配置项可以使组件更方便地接收路由参数

{name: 'route1',path: '/detail/:id',component: Detail,// 第一种写法: props值为对象, 该对象中所有的k-v最终都会通过props传给detail组件props: {a:900}// 第二种写法: boolean, 把路由中的所有params参数通过props传给Detail组件props: true// 第三种写法: props值为函数, 会把函数返回的对象的所有k-v通过props传给Detail组件props(route) {return {id: route.query.id,title: route.query.title}}
}
<router-link>的replace属性

浏览器的历史记录有两种写入方式分别是pushreplace, push是追加历史记录, replace则是替换当前记录. 路由跳转时候默认是push. 可以通过以下配置开启repalce模式

<router-link replace ...>News</router-link>
编程式路由导航

编程式路由可以不借助<router-link>实现路由跳转, 让路由跳转更加灵活

this.$router.push({name: 'path',params: {id: xxx,title: xxx}
})this.$router.replace({name: 'path',params: {id: xxx}
})this.$router.back()
this.$router.forward()
this.$router.go(3) // 正数前进, 负数后退
缓存路由组件

让不展示的路由组件保持挂载, 不被销毁. 缓存多个组件可以写数组

<!-- 要写组件名称 --> 
<keep-alice include="News"><router-view></router-view>
</keep-alice>
两个新的生命周期钩子

路由组件独有的两个钩子, 用于捕获路由组件的激活状态

  1. activated: 路由组件被激活时触发
  2. deactivated: 路由组件失活时触发
路由守卫

路由守卫可以对路由进行权限控制, 包括全局守卫、独享守卫、组件内守卫.

// 前置全局守卫 初始化时执行、每次路由切换前执行
router.beforeEach((to, from, next) => {if(to.meta.isAuth) {if(condition) {next() // 满足条件放行,}}
})// 后置
router.afterEach((to, from) => {if(to.meta.title) {// ...}
})// 独享守卫, 在具体的路由配置项中配置
beforeEnter(to, from, next) {}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/513582.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript观察者模式:实现对象间的事件通信!

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

UOS 20 安装redis 7.0.11 安装redis 7.0.11时 make命令 报错 /bin/sh: cc: command not found

UOS 20 安装redis 7.0.11 1、下载redis 7.0.112、安装redis 7.0.113、启动停止redis 7.0.114、安装过程问题记录 UOS 20 安装redis 7.0.11 安装redis 7.0.11时 make命令 报错 /bin/sh: cc: command not found、zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such fil…

【Redis】Redis 缓存重点解析

Redis 缓存重点解析 推荐文章&#xff1a;【Redis】Redis的特性和应用场景 数据类型 持久化 数据淘汰 事务 多机部署-CSDN博客 1. 我看你的项目都用到了 Redis&#xff0c;你在最近的项目的哪些场景下用到了 Redis 呢&#xff1f; 一定要结合业务场景来回答问题&#x…

数字化转型导师坚鹏:成为数字化转型顾问 引领数字化美好未来

成为数字化转型顾问 引领数字化美好未来 ——数字化人才与企业的共赢之路 数字经济新时代&#xff0c;中国企业向数字化转型要效益&#xff1b; 转型顾问创未来&#xff0c;职场精英借数字化转型成良师。 我们中国政府特别重视数字经济发展及数字化人才培养。早在2020年8月2…

消息队列-kafka-服务端处理架构(架构,Topic文件结构,服务端数据的一致性)

服务端处理架构 资料来源于网络 网络线程池&#xff1a; 接受请求&#xff0c;num.network.threads&#xff0c;默认为 3&#xff0c;专门处理客户的发送的请求。 IO 线程池&#xff1a; num.io.threads&#xff0c;默认为 8&#xff0c;专门处理业务请求。也就是它不负责发…

浅析扩散模型与图像生成【应用篇】(六)——DiffuseIT

6. Diffusion-based Image Translation using Disentangled Style and Content Representation 本文介绍了一种基于扩散模型的图像转换方法&#xff0c;图像转换就是根据文本引导或者图像的引导&#xff0c;将源图像转换到目标域中&#xff0c;如下图所示。   在图像转换中待…

拼多多3.9元的手机支架,在视频号卖15.9元

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 万万没想到&#xff1a;拼多多3.9元的手机支架&#xff0c;在视频号竟然要卖15.9元。 更让人想不到的是&#xff1a;视频号商家竟然是从拼多多发货的&#xff0c;足足赚了4倍差价。 更更更让人想不到的是&#xff1a…

Vanna-ai -基于RAG的TextToSql实现方案

官方连接&#xff1a;Vanna.AI - Personalized AI SQL Agent 1.背景 基于大模型的TextToSql的关键为给大模型提供正确有效的数据库信息及问题&#xff0c;以提升大模型生成sql的正确率。database_info question形成prompt&#xff0c;但是实际中通常会遇到一个问题&#xff…

文物保护平台数据统计分析及预警-子系统专题分析

文物预防性监测与调控系统的监测统计分析子系统提供全面的文物状态及环境数据分析,为博物馆工作人员进行基于文物材质特性的专项保护提供相关科研辅助。主要的监测分析,包括各展厅文物统计分析、不同环境因素报表统计、以及监测调控设备统计分析等。 系统用户和文物管理人员可以…

商城免费搭建之java商城 java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

【论文阅读】(DALLE-3)Improving Image Generation with Better Captions

&#xff08;DALLE-3&#xff09;Improving Image Generation with Better Captions 文章目录 &#xff08;DALLE-3&#xff09;Improving Image Generation with Better Captions简介Method实验 引用&#xff1a; Betker J, Goh G, Jing L, et al. Improving image generation…

外包干了3个月,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…