Vue(二)
1.Vue生命周期
Vue生命周期就是一个Vue实例从 创建 到 销毁 的整个过程。生命周期四个阶段:
-
创建阶段:创建响应式数据。
-
挂载阶段:渲染模板。
-
更新阶段:修改数据,更新视图。
-
销毁阶段:销毁Vue实例。
2.Vue生命周期钩子
Vue生命周期有四个阶段,对应了八个钩子函数,如下图所示。这些函数会在生命周期当中自动运行,让开发者在特定阶段运行自己的代码。比如:
-
created:创建响应式数据之后,可以利用此函数请求服务端,拿到数据对响应式数据进行初始化。
-
monted:模板渲染完成后,可以利用此函数操作Dom,比如获取焦点。
-
before Destroy:销毁Vue实例之前,对一些资源进行释放。
3.工程化开发和脚手架
使用Vue进行开发有二种方式,第一种是核心包传统开发模式,这种开发模式不依赖任何构建工具,直接使用 html、css 和 js 文件,通过引入 Vue 的核心库来开发应用。这种方式适用于简单的应用或者学习场景。
在基于构建工具(例如:webpack)的环境中使用Vue进行开发,适合中大型项目。
-
工程化开发模式优点:提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等。
-
工程化开发模式问题:webpack配置起来不简单、雷同的基础配置、缺乏统一的标准。
为了解决以上问题,所以我们需要一个工具,生成标准化的配置。Vue CLI 是Vue官方提供的一个全局命令工具,集成了webpack配置。可以帮助我们快速创建一个开发Vue项目的标准化基础架子。
3.1 VueCLI自动创建项目
1.在命令行中输入以下命令,进行全局安装,电脑中只需要安装一次即可
yarn global add @vue/cli 或者 npm i @vue/cli -g
2.查看vue/cli版本
vue --version
3.创建项目架子
vue create project-name
4.启动项目
yarn serve 或者 npm run serve(命令不固定,找package.json)
3.2 VueCLI自定义创建项目
VueCLI自动创建出的项目,在某些时候可能缺少我们需要的配置,这种情况下我们要进行大量的配置。因此,我们也可以通过VueCLI自定义创建项目。
1.安装脚手架
npm i @vue/cli -g
2.创建项目
vue create hm-exp-mobile
在弹出的界面中选择自定义
Vue CLI v5.0.8
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
> Manually select features 选自定义
手动选择功能 :这里勾选了对应的功能,项目里就会给你初始化好对应的内容
选择vue的版本
3.x
> 2.x
是否使用history模式
选择css预处理
选择eslint的风格 (eslint 代码规范的检验工具,检验代码是否符合规范)。比如:const age = 18; => 报错!多加了分号!后面有工具,一保存,全部格式化成最规范的样子
选择校验的时机 (直接回车)
选择配置文件的生成方式 (直接回车)
是否保存预设,下次直接使用? => 不保存,输入 N
等待安装,项目初始化完成
启动项目
npm run serve
3.3 项目目录
下面是通过 Vue CLI 创建出的项目,各个目录及文件的含义如下图所示。
3.4 运行流程
4.组件化开发
一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。组件化开发能够提高项目的可维护性和可复用性。每个组件由三部分构成,分别是:
-
template:结构
-
script: js逻辑
-
style: 样式 (可支持less,需要装包)
组件有普通组件、根组件二种类型。
4.1 根组件App.vue
整个应用最上层的组件,包裹所有普通小组件。
4.2 组件的注册使用
1.局部注册
局部注册只能在注册的组件内使用。使用步骤如下:
-
创建.vue文件,编写三个组成部分。创建出的组件一般放在components文件夹下。
-
在使用的组件内先导入再注册,
-
在注册的组件中当成html标签使用即可。
// 导入需要注册的组件
import HmHeader from './components/HmHeader'
export default { //局部注册
components: {
HmHeader: HmHeaer, //组件名: 组件对象。组件名和组件对象名字相同时,可简化为:HmHeader
}
}
//在注册的组件中当成html标签使用即可
<组件名></组件名>
2.全局注册
全局注册的组件,在项目的任何组件中都能使用。使用步骤如下:
-
创建.vue组件(三个组成部分)
-
main.js中进行全局注册
-
在需要使用的组件中,当成html标签使用即可
//在main.js中进行注册
import HmButton from './components/HmButton' //导入需要全局注册的组件
Vue.component('HmButton', HmButton) //进行注册
//在需要使用的组件中当成html标签使用即可
<组件名></组件名>
5.scoped解决样式冲突
写在组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。可以给组件中的 <style> 标签加上scoped 属性,让样式只作用于当前组件。
6.data必须是一个函数
一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。每次创建新的组件实例,都会新执行一次 data 函数,得到一个新对象。
7.组件通信
组件通信,就是指组件与组件之间的数据传递。组件之间的关系可分类父子关系和非父子关系,针对不同的组件关系,有不同的数据传递方案。
7.1 父向子通信
7.2 子向父通信
7.3 props校验
组件的 prop 可以指定验证要求,不符合要求,控制台就会有错误提示,能帮助开发者,快速发现错误。
props: {
校验的属性名: {
type: 类型, // Number String Boolean ...
required: true, // 是否必填
default: 默认值, // 默认值
validator (value) {
// 自定义校验逻辑
return 是否通过校验
}
}
},
如果只需要对类型校验,则可以采用简写形式。
props: {
校验的属性名: 类型
}
7.4 非父子通信-event bus事件总线
非父子组件之间,进行简易消息传递,可以采用"event bus 事件总线 "。复杂场景下还是采用Vuex。非父子通信的步骤如下:
创建一个都能访问的事件总线,并进行导出。通常放到一个公共的js文件里。
import Vue from 'vue'
const Bus = new Vue()
export default Bus
A组件(接受方),监听Bus的 $on事件
created () {
Bus.$on('sendMsg', (msg) => {
this.msg = msg
})
}
B组件(发送方),触发Bus的$emit事件
Bus.$emit('sendMsg', '这是一个消息')
7.5 非父子通信-provide&inject
provide&inject用来跨层级共享数据。需要注意的是,provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。
父组件 provide 提供数据
export default {
provide () {
return {
// 普通类型【非响应式】
color: this.color,
// 复杂类型【响应式】
userInfo: this.userInfo,
}
}
}
子/孙组件 inject 获取数据
export default {
inject: ['color','userInfo'],
created () {
console.log(this.color, this.userInfo)
}
}
8.父子组件的双向数据绑定
8.1 通过v-model实现
v-model原理:v-model 本质上是一个语法糖。不同的表单元素, v-model在底层的处理机制是不一样的。例如应用在输入框上,就是 value 属性 和 input 事件的合并,。不过咱们只需要掌握应用在文本框上的原理即可。
<template>
<div id="app" >
<input v-model="msg" type="text">
//数据变,视图跟着变(:value的作用)。视图变,数据跟着变(@input的作用)。
<input :value="msg" @input="msg = $event.target.value" type="text">
</div>
</template>
我们可以将 v-model 拆解开来,实现父组件和子组件中数据的双向绑定。
//父组件
<template>
<div class="app">
<BaseSelect
:selectId="selectId"
@changeCity="selectId = $event"
></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
},
}
</script>
<style>
</style>
//下拉框组件(子组件)。App.vue中的数据和此组件的数据实现了双向数据绑定
<template>
<div>
<select :value="selectId" @change="selectCity">
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props: {
selectId: String,
},
methods: {
selectCity(e) {
this.$emit('changeCity', e.target.value)
},
},
}
</script>
<style>
</style>
父组件中可以通过 v-model 的原理进一步简化代码
//父组件中,v-model可以拆解成:value和@input
<BaseSelect v-model="selectId"></BaseSelect>
//子组件
<select :value="value" @change="handleChange">...</select>
props: {
value: String //父组件如果用v-model传值,则props中只能使用value来接收数据
},
methods: {
handleChange (e) {
this.$emit('input', e.target.value)
}
}
8.2 通过.sync修饰符
.sync修饰符也是用来实现父组件和子组件的双向数据绑定。相比于在父组件中使用v-model传值给子组件,子组件的props中必须使用value接收数据,.sync可以
//父组件
//简单写法
<BaseDialog :visible.sync="isShow" />
--------------------------------------
//上述写法等价于下面
<BaseDialog
:visible="isShow"
@update:visible="isShow = $event"
/>
//子组件
props: {
visible: Boolean
},
this.$emit('update:visible', false)
10.ref和$refs
利用 ref 和 $refs 可以用于获取当前组件内的"dom 元素"或者"组件实例",避免了普通 JavaScript 中通过全局 DOM 查找元素时可能产生的错误。
10.1 获取dom元素
1.在想要获取的标签上添加 ref 属性
<div ref="chartRef">我是渲染图表的容器</div>
2.通过 this.$refs.chartRef 获取目标标签
mounted () {
console.log(this.$refs.chartRef)
}
10.2 获取组件实例
1.在父组件中给目标组件添加 ref 属性
<BaseForm ref="baseForm"></BaseForm>
2.通过 "this.$refs.目标组件名" 获取目标组件实例。获取到目标组件的实例之后,就可以通过这个实例获取组件中的数据和调用实例中的方法。
this.$refs.baseForm.组件方法()
11.异步更新($nextTick)
DOM更新完成后,nextTick 里的函数体会自动异步执行。
//nextTick在方法中使用
this.$nextTick(() => {
this.$refs.inp.focus()
})