第一章 Vue2入门基础 v1.0
第一部分 Vue入门
一、Vue2基本语法
1.基本使用示例
<!--1.引入Vue依赖(此为Vue2)-->
<script src="../module/vue.js"></script>
<!--2.准备容器-->
<div id="box">
{{ msg }}
</div>
<!--3.创建Vue对象并挂载-->
<script>
const app=new Vue({
el:"#box", //挂载点
data:{ //数据,在外部可以通过对象获取或修改(此处对象为app),如app.msg
msg:"msg"
},
methods:{} //内联函数
});
</script>
2.插值表达式
Vue的一种模板语法,利用表达式进行插值,渲染到页面中
语法:{{ 表达式 }}
注意要点: ①数据需要预定义 ②支持表达式而非语句 ③不能再标签属性中使用
3.Vue指令
HTML标签上带有v-前缀的特殊属性,不同指令有不同作用
v-bind
(v-bind:
可缩写为:
):为HTML标签绑定属性值v-html
:控制元素内的html渲染v-model
:在表单元素上创建双向数据绑定v-on
(v-on
:可缩写为@
):为HTML元素绑定事件v-show
:通过控制display属性控制元素的隐藏v-if
/v-else-if
/v-else
:通过条件判断控制元素的渲染与删除v-for
:列表渲染,遍历容器的元素或对象的属性
①v-for
标准语法:v-for="(item,index) in iterator" :key="item.id"
key
的作用:为元素添加唯一标识,便于Vue进行列表的正确排序复用,必须具有唯一性
②v-bind
对于样式控制的增强
- 操作class对象:
<div :class="{ 类名1:布尔值, 类名2:布尔值 }">
- 操作class数组:
<div :class="[ 类名1, 类名2, 类名3 ]">
- 操作style:
<div :style="{ 属性名1:属性值, 属性名2:属性值 }">
③v-model
v-model原理:本质上是一个语法糖,应用在输入框上就是:value
和@input
的合写,作用是提供双向数据绑定
<input v-model="msg" type="text"> <!-- 等价于下方写法 -->
<input :value="msg" @input="msg = $event.target.value" type="text">
:value
:修改视图,数据随视图变化而变化@input="msg = $event.target.value"
:数据变化视图自动更新
当v-model绑定不同表单元素时绑定不同的数值:
input
/textarea
:输入内容(字符串)checkbox
:是否选中(布尔值)radio
:选中的value值(字符串)select
:选中的value值(字符串)
二、指令修饰符
通过
.
指明一些指令后缀,不同后缀封装了不同的处理操作,简化一些操作
1.常用事件指令修饰符
@keyup.enter
:监听键盘回车按键,之后执行指定操作@事件名.stop
:阻止冒泡@事件名.prevent
:阻止默认行为
2.v-model指令修饰符
v-model.trim
:去除绑定数据的前后空格v-model.number
:将绑定内容转换为数字
三、计算属性(computed)
1.基本概念
定义:基于现有的数据计算所得到的新属性,依赖的数据变化,自动重新计算
使用:声明在computed配置项中,一个属性对应一个函数,使用可以和普通属性一样使用
2.语法
compyted:{
property() { //调用只需使用 {{ property }} 即可
//数据操作逻辑
return data;
}
}
compyted:{
property: { //调用只需使用 {{ property }} 即可
get() {
//数据操作逻辑
return data;
},
set(value) { //修改赋值时操作
//数据修改逻辑
}
}
}
四、watch监听器
监视数据变化,执行一些业务逻辑或异步操作
1.语法
const app=new Vue({
el:'#app',
data: {
words: ''
},
watch: {
words(newValue, oldValue){
console.log("变化了", newValue, oldValue);
}
}
})
const app=new Vue({
el:'#app',
data: {
obj: {
words: ''
}
},
watch: {
'obj.words'(newValue, oldValue){
console.log("变化了", newValue, oldValue);
}
}
})
// 可以添加额外配置项
const app=new Vue({
el:'#app',
data: {
obj:{
words: '',
anotherWords: ''
}
},
watch: {
obj: {
deep: true, // 复杂类型深度监视,监视复杂对象中的所有属性变化
immediate: true, // 初始化页面立即执行一次
handler (newValue, oldValue){
console.log("变化了", newValue, oldValue);
}
}
}
})
2.示例
const app=new Vue({
el:'#app',
data: {
obj: {
words: ''
}
},
watch: {
async 'obj.words'(newValue){
const res = await axios({
url:"http://...",
params:{
words: newValue
}
})
console.log(res.data.data)
}
}
})
const app=new Vue({
el:'#app',
data: {
obj: {
words: ''
},
result: ''
},
watch: {
'obj.words'(newValue){
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
const res = await axios({
url:"http://...",
params:{
words: newValue
}
})
this.result = res.data.data
console.log(res.data.data)
},300)
}
}
})
五、生命周期
1.生命周期
一个Vue实例从创建到销毁的整个过程,共有四个阶段,分别是: ①创建 ②挂载 ③更新 ④销毁
2.生命周期函数(钩子函数)
①简介
Vue生命周期过程中,会自动运行一些函数,被称为生命周期钩子,让开发者可以在特定阶段运行自己的代码。
②使用示例
const app = new Vue({
el: "#app",
data: {
list: []
},
async created (){
const res = await axios.get("...")
this.list = res.data.data
}
})
const app = new Vue({
el: "#app",
mounted() {
document.querySelector('#inp').focus() // 选择元素并聚焦
}
})
第二部分 工程化开发
一、脚手架
1.使用VueCli创建Vue工程
Vue官方提供的一个全局命令工具,可以帮助我们快速创建一个开发Vue项目的标准化基础架子(集成了webpack配置)
npm和yarn都是管理第三方包的,使用VueCli的步骤如下:
npm i @vue/cli -g # 安装脚手架
vue --version # 查看Vue版本
vue create <project-name> # 创建项目
npm run serve # 启动项目
yarn global add @vue/cli # 安装脚手架
vue --version # 查看Vue版本
vue create <project-name> # 创建项目
yarn serve # 启动项目
2.其他创建方法
create-vue是官方新的脚手架工具,底层切换到了vite,默认版本为Vue3,相较于webpack,响应更快
npm create vue@latest
>> 输入模块名
>> 配置选项
cd <模块名>
npm i #安装相关依赖
npm run dev #运行
npm create vite@latest
>> 输入模块名
>> 配置选项
cd <模块名>
npm i #安装相关依赖
npm run dev #运行
3.目录结构
vue-project
├- node_modules [第三方包文件夹]
├- src [源代码目录]
├- assets [静态资源目录] 存放文件、字体等
├- router [路由目录] 存放路由管理的js文件
├- views [页面组件] 页面展示相关组件,配合路由使用
├- components [复用组件] 展示数据相关组件,常用于复用
├- App.vue App根组件
└- main.js 入口文件,打包运行时第一个执行的文件
├- public [静态资源目录]
├- jsconfig.json js配置文件
├- package.json 项目配置文件,包含项目名、版本号、依赖包等
└- vue.config.js vue配置文件(vite则为vite.config.js)
二、路径别名
在Vue中(webpack配置),引入文件时可以通过
@路径
代表根路径(以src
为根)
例:import MyCom from '@/views/MyCom'
在Vue中,我们可以通过对应config.js中修改选项,自己定义相关路径别名
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve("src") // 相对路径别名配置,使用 @ 代替 src
}
}
})
三、代码结构
1.main.js
核心作用:导入App.vue, 基于App.vue创建结构渲染index.html
// 1.导入Vue 核心包
import Vue from 'vue'
// 2.导入App.vue 根组件
import App from './App.vue'
//提示:当前处于什么环境(生产环境/开发环境)
Vue.config.productionTip = false
// 3. Vue实例化,提供render方法 -> 基于App.vue创建结构渲染index.html
new Vue({
render: h => h(App),
}).$mount('#app')
// 1.导入Vue 核心包
import Vue from 'vue'
// 2.导入App.vue 根组件
import App from './App.vue'
//提示:当前处于什么环境(生产环境/开发环境)
Vue.config.productionTip = false
// 3. Vue实例化,提供render方法 -> 基于App.vue创建结构渲染index.html
new Vue({ //指定Vue管理的容器
el:'#app',
render: (createElement) => { //完整写法
return createElement(App)
},
})
2.App.vue
App组件,在其核心代码结构同时也是组件结构,详见组件化
<template>
<!-- 模板结构 -->
</template>
<script>
//js逻辑结构
</script>
<style lang='less'>
/* 样式结构 */
</style>
<template>
<!-- 模板结构,有且只能有一个根元素(Vue2,Vue3无限制) -->
</template>
<script>
export default {
//导出的是当前组件的配置项
//可以提供 data methods computed watch 生命周期钩子函数
data:{
//...
}
}
</script>
<style lang='less' scoped>
/* 样式,默认不支持less,需要装包,npm install less less-loader */
/*
style中样式默认为全局样式,容易造成多个组件的样式冲突问题;添加scoped为局部样式,只作用于当前组件
scoped原理:
1.给组件所有元素添加一个自定义属性data-v-hash值
2.在css选择器后自动处理,在后面添加了属性选择器,如:div[data-v-hash]
*/
</style>
第三部分 组件化
组件化开发是Vue构建大型、可维护前端应用的关键实践。组件化允许开发者将界面划分为独立的、可复用的组件,每个组件都有自己的逻辑和样式。
一、定义组件
使用一个.vue文件来定义组件,和前面App.vue一样,包含三个部分
1.单文件组件
<template>
<!-- 模板结构 -->
</template>
<script>
//js逻辑结构
</script>
<style lang='less'>
/* 样式结构 */
</style>
<template>
<div class="my-component">
<h1>{{ message }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Component!'
};
}
};
</script>
<style scoped>
.my-component h1 {
color: blue;
}
</style>
2.data
一个组件的data选项是一个函数,用于维护每个组件实例一份独立的数据对象
<script>
export default {
data () {
return {
count: 1000
}
}
}
</script>
3.props
组件上注册的一些自定义属性,可以传递任意数量,任意类型的变量
<script>
export default {
props: ['element1', 'element2', ...]
}
</script>
props校验: 为组件的prop指定校验要求,不符合要求,控制台就会有错误提示,可以帮助开发者快速发现错误
<script>
export default {
props: {
element1: Number,
element2: String,
func1: Function
}
}
</script>
<!--复杂校验:可以进行类型、非空、默认值设置、自定义校验规则校验-->
<script>
export default {
props: {
属性名: {
type: 属性, //属性校验
required: true, //是否必填
default: 默认值, //设置默认值
validator (value) { //自定义校验逻辑
if(condition) { //通过验证条件
return true
} else {
console.error("错误描述")
return flase
}
}
}
}
}
</script>
二、组件注册
在 Vue 2 中,你可以通过 Vue.component() 方法全局注册组件,或者在特定 Vue 实例中通过 components 选项局部注册。
1.局部注册(只能在注册的组件内使用)
使用步骤: ①创建.vue文件 ②在使用的组件内导入并注册
使用方法: 直接当成html标签使用:<标签名></标签名>
(使用大驼峰命名)
<template>
<组件名></组件名> <!-- 使用组件 -->
</template>
<script>
import <组件名> from 'Xxx.vue'
export default {
components: {
<组件名> // 完整写法为 <组件名>: <组件对象>
}
}
</script>
2.全局注册(所有组件内都能使用)
使用步骤: ①创建.vue文件 ②在main.js中进行全局注册
import <组件名> from 'Xxx.vue'
// 规范:导入的代码在main.js的顶部编写
Vue.component(组件名,组件对象)
三、组件通信
1.常见组件通信解决方案
- 父子组件: props和$emit
- 非父子组件: provide&inject、enentbus
- 通用解决方案: Vuex
2.父子组件通信
父传子
<template>
<Son :title="myTitle"></Son> <!-- 指定传值给Son的title属性 -->
</template>
<script>
import Son from 'Son.vue'
export default {
data () {
return {
myTitle: "my_title"
}
},
components: {
Son
},
}
</script>
<template>
{{ title }}
</template>
<script>
export default {
props: ['title'] //可以接受父组件传递的值
}
</script>
子传父
<template>
<div>{{ title }}</div>
<button @click="changeT">修改Title</button>
</template>
<script>
export default {
props: ['title'],
methods: {
changeT() { //通过$emit向父组件发送消息通知
this.$emit("changeTitle", "修改后的标题")
}
}
}
</script>
<template>
<Son :title="myTitle" @changeTitle="handleChange"></Son> <!-- 指定接收消息后的处理函数 -->
</template>
<script>
import Son from 'Son.vue'
export default {
methods: {
handleChange (newTitle) { //处理函数
this.myTitle = newTitle
}
},
data () {
return {
myTitle: "my_title"
}
},
components: {
Son
},
}
</script>
3.非父子组件通信
跨层级共享数据(provide&inject)
<script>
export default {
provide () {
return {
属性1: this.属性1,
属性2: this.属性2,
}
},
data () {
return {
属性1: "1", //简单类型(非响应式)
属性2: { //复杂类型(响应式,推荐使用)
属性3: '3',
属性4: '4'
},
}
}
</script>
<script>
export default { //被包含在内的组件直接通过inject获取属性
inject: ['属性1','属性2']
}
</script>
事件总线(enent bus)
import Vue from 'vue'
//创建一个都能访问到的事件总线(空的Vue实例)
const Bus = new Vue()
export default Bus
<script>
import Bus from 'utils/EventBus'
export default {
created () { //在接收方监听Bus的事件(订阅消息)
Bus.$on('sendMsg', (msg) => {
//接收消息后的主要代码逻辑
})
}
}
</script>
<template>
<button @click="clickSend">发布通知</button>
</template>
<script>
import Bus from 'utils/EventBus'
export default {
methods: {
clickSend () {
//触发并发送消息
Bus.$emit("sendMsg","msg")
}
}
}
</script>
4.表单类组件封装
<template>
<!-- 3.监听数据变化,使用$event直接接收传值结果 -->
<Son :selectId="selectId" @changeTitle="selectId = $event"></Son>
</template>
<script>
import Son from 'Son.vue'
export default {
data () {
return {
selectId: "100"
}
},
components: {
Son
},
}
</script>
<template>
请输入selectId:<input :value="selectId" @change="handleChange"></input>
</template>
<script>
export default {
props: {
selectId: String //1.不能使用v-model,使用 :value 绑定渲染数据
},
methods: {
handleChange (e) {
this.$emit("changeId", e.target.value) //2.传递修改的数据
}
}
}
</script>
表单类组件封装(使用v-model优化)
<template>
<!-- 修改为v-model 原理:v-model => :value + @input -->
<Son v-model="selectId"></Son>
</template>
<script>
import Son from 'Son.vue'
export default {
data () {
return {
selectId: "100"
}
},
components: {
Son
},
}
</script>
<template>
<!-- 2.修改为value绑定数据 -->
请输入selectId:<input :value="value" @change="handleChange"></input>
</template>
<script>
export default {
props: {
value: String //1.修改属性为value接收
},
methods: {
handleChange (e) {
this.$emit("input", e.target.value) //3.事件名修改为input
}
}
}
</script>
5.弹窗类组件封装
.sync
修饰符可以实现子组件与父组件数据的双向绑定,简化代码,props属性名可以自定义
本质::visible.sync="isShow"
等价于:visible="isShow"
和@update:visible="isShow = $event"
<template>
<BaseDialog :visible.sync="isShow" />
</template>
<template>
<BaseDialog :visible="isShow"
@update:visible="isShow = $event" />
</template>
<script>
export default {
props: {
visible: Boolean
},
methods:{
close() {
// 当触发close时,修改对应visible属性值
this.$emit('update:visible', false)
}
}
}
</script>
四、操作dom元素
1.querySelector
作用: 查找整个页面中制定选择器的页面元素
语法:document.querySelector('选择器')
2.ref 和 $refs
作用: 通过ref属性可以查找指定元素(但需要页面渲染完后才能获取),查找范围是当前组件内,更加精确稳定。且利用 ref 和 $refs 不仅可以用来操作dom元素,还可以操作组件实例调用组件对象中的方法
<template>
<div ref="myRef"><!-- 1.添加ref属性 -->
...
</div>
</template>
<script>
export default {
mounted() { // 在实例挂载后修改内容,修改div中内容为 "123"
this.$refs.myRef.innerText = '123'; // 2.页面渲染完通过 this.$refs.myRef 获取元素
}
};
</script>
<template>
<BaseModule ref="myRef" /><!-- 1.添加ref属性 -->
</template>
<script>
export default {
mounted() { // 在实例挂载后立刻调用组件方法
this.$refs.myRef.func(); // 2.页面渲染完通过 this.$refs.myRef 获取元素
}
};
</script>
3.Vue异步dom更新
Vue是异步更新dom的,要等dom更新后再操作,可以使用$nextTick
$nextTink
作用:等dom更新完之后,立即执行函数体中的操作
<script>
export default {
methods: {
handleUpdateDom (){
// 1.显示dom元素(执行dom更新)
this.showDom = true
// 2.获取焦点
this.$nextTink(() => {
this.$refs.inp.focus() //执行下一步更新
})
}
}
}
</script>
<script>
export default {
methods: {
handleUpdateDom (){
// 1.显示dom元素(执行dom更新)
this.showDom = true
// 2.延时执行,获取焦点
setTimeout(() => {
this.$refs.inp.focus() //执行下一步更新
}, 300)
}
}
}
</script>