1、快速上手
1)概念
2)创建实例
3)插值表达式 {{}}
插值表达式是一种Vue的模板语法。
(1)作用:
利用表达式进行插值,渲染到页面中表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
(2)语法:{{表达式}}
<h3>{{title}}</h3>
<p>{{nickname.toUpperCase}}</p>
<p>{{age>=18?'成年':'未成年'}}</p>
<p>{{obj.name}}</p>
(3)注意点:
①使用的数据必须存在(data)
②支持的是表达式,而非语句,比如:if for....
{{if}}//有误
③不能在标签属性中使用{{}}插值
<p title="{{username}}">我是p标签</p>//有误
3)响应式特性
(1)什么是响应式
数据改变,视图自动更新
(2)如果访问或修改数据
data中的数据,最终会被添加到实例上:
①访问数据:“实例.属性名”
②修改数据:“实例.属性名”=“值”
2、指令
Vue根据不同的【指令】,针对标签实现不同的【功能】。
指令:带有v-前缀
的特殊标签属性
普通标签属性:
<div class="box">...</div>
<div title="小张">...</div>
Vue指令:
<div v-html="str">...</div>
1)v-html
(1)作用:设置元素的innerHTML
(2)语法:v-html="表达式"
2)v-show
(1)作用:控制元素显示隐藏
(2)语法:v-show="表达式"
,表达式值true显示,false隐藏
(3)原理:切换display:none控制显示隐藏
(4)场景:频繁切换显示隐藏的场景
3)v-if
(1)作用:控制元素显示隐藏(条件渲染)
(2)语法:v-if="表达式"
,表达式值true显示,false隐藏
(3)原理:基于条件判断,是欧服创建或移除元素节点
(4)场景:要么显示,要么隐藏,不频繁切换的场景
4)v-else、v-else-if
(1)作用:辅助v-if进行判断渲染
(2)语法:v-else
和v-else-if="表达式"
(3)注意:需要紧挨着v-if一起使用
5)v-on
(1)作用:注册事件=添加监听+提供处理逻辑
(2)语法:
①v-on:事件名="内嵌语句"
②v-on:事件名="methods中的函数名"
(3)简写:@事件名="函数或内嵌语句"
<button v-on:click="count++">按钮</button>
<button v-on:click="fn">按钮</button>
<button @click="count++">按钮</button>
注意:methods函数内的this指向Vue实例
6)v-bind
(1)作用:动态的设置html的标签属性,如src、url、title...
(2)语法:v-bind:属性名="表达式"
(3)简写形式::属性名="表达式"
<img v-bind:src="url">
<img :src="url">
const app=new Vue({
el:'#app',
data:{
url:"图片路径"
}
})
(4)v-bind对于样式控制的增强-操作class
语法::class="对象/数组"
①对象:键就是类名,值是布尔值,如果值为true,有这个类,否则没有这个类
<div :class="{类名1:布尔值,类名2:布尔值}"></div>
通用场景:一个类名来回切换
②数组:数组中所有的类,都会加到盒子上,本质就是一个class列表
<div :class="[类名1,类名2]"></div>
通用场景:批量添加或者删除类
(5)v-bind对于样式控制的增强-操作style
语法::style="样式对象"
<div :style="{css属性名1:css属性值1,css属性名2:css属性值2}"></div>
7)v-for
(1)作用:基于数据循环,多次渲染整个元素。(数组、对象、数字....)
<p v-for="">内容</p>
(2)遍历数组语法:
v-for="(item,index) in 数组"
item为每一项,index为下标
省略index:v-for="item in 数组"
(3)v-for中的key
①语法:key属性="唯一标识"
②作用:给列表项添加唯一标识,便于vue进行列表项的正确排序复用。
<ul>
<li v-for="(item,index) in booksList" :key="item.id">
<span>{{item.name}}</span>
</li>
</ul>
③注意点:
key的值只能是字符串或数字类型;
key的值必须具有唯一性;
推荐使用id作为key,不推荐使用index(会变化,不对应)作为key;
7)v-model
(1)作用:给表单元素使用,双向数据绑定,可以快速获取或设置表单元素内容
①数据变化,视图自动更新
②视图变化,数据自动更新
(2)语法:v-model="变量"
(3)v-model应用于其他表单元素
常见的表单元素可以用v-model绑定关联,它会根据控件类型自动选取正确的方法来更新元素。
类型 | 关联 |
---|---|
输入框 input:text | value |
文本域 textarea | value |
复选框 input:checkbox | checked |
单选框 input:radio | checked |
下拉菜单 select | value |
8)指令修饰符
通过“."
指明一些指令后缀,不同后缀封装了不同的处理操作,简化了代码。
①按键修饰符:@keyup.enter
键盘回车监听
②v-model修饰符:
v-model.trim
去除首尾空格
v-model:number
转数字
③事件修饰符
@事件名.stop
阻止冒泡
@事件名.prevent
阻止默认行为
3、计算属性
(1)概念:基于现有的数据,计算出来的新属性,依赖的数据变化,自动重新计算。
缓存特性(提升性能)
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算,并再次缓存
(2)语法:
①声明在computed
配置项中,一个计算属性对应一个函数
②使用起来和普通属性一样使用{{计算属性名}}
计算属性可以将一段
求值的代码
进行封装
computed:{
计算属性名(){
//一段代码逻辑(计算逻辑)
return 结果
}
}
(3)computed计算属性和method方法
①computed计算属性:封装了一段对于数据的处理,求得一个结果
写在computed配置项中,作为属性直接使用:this.计算属性、{{计算属性}}
②methods方法:给实例提供 一个方法,调用以处理业务逻辑
写在methods配置项中,作为方法,需要调用:this.方法名()、{{方法名}}、@事件名="方法名"
(4)计算属性完整写法
计算属性默认的简写,只能读取访问,不能“修改”,如果要“修改”,需要写计算属性的完整写法。
computed:{
计算属性名:{
get(){
//一段代码逻辑(计算逻辑)
return 结果
},
set(修改的值){
//一段代码逻辑(计算逻辑)
}
}
}
4、watch侦听器(监视器)
(1)作用:监视数据变化,执行一些业务逻辑或异步操作
(2)语法:
①简单写法:简单数据类型,直接监视
data:{
words:'苹果',
obj:{words:'苹果'}
},
watch{
//该方法会在数据变化时,触发执行
数据属性名(newValue,oldValue){
//一些业务逻辑或异步操作
},
'对象.属性名'(newValue,oldValue){
//一些业务逻辑或异步操作
}
}
②完整写法:添加额外配置项
对复杂类型深度监视:deep:true
初始化立刻执行一次handler方法:immediate:true
data:{
obj:{
words:'苹果',
lang:'italy'
}
},
watch:{
数据属性名:{
deep:true,//对obj的words和lang同时监视,任意一项变化
handler(newValue){
//一些业务逻辑或操作
}
}
}
eg.
点击查看代码
<div id="app">
<div>
<span>翻译成的语言:</span>
<select v-model="lang">
<option value="italy">意大利</option>
<option value="english">英语</option>
</select>
</div>
<div>
<div>
<textarea v-model="obj.words"></textarea>
</div>
<div>
<div>{{result}}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.js"></script>
<script>
//https://applet-base-api-t.itheima.net/api/translate
const app = new Vue({
el: "#app",
data: {
obj: {
words: '小黑',
lang: 'italy'
},
result: '',
},
watch: {
obj: {
deep: true,
immediate: true,
handler(n) {
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: 'n'
})
this.result = res.data.data
console.log(res.data.data)
})
}
}
}
})
</script>
5、生命周期
Vue生命周期:一个Vue实例从创建到销毁的整个过程。
生命周期四个阶段:创建、挂载、更新、销毁
Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】,让开发者可以在【特定阶段】运行自己的代码。
6、工程化开发入门
开发Vue的两种方式:
①核心包传统开发模式:基于html/css/js文件,直接引入核心包,开发Vue
②工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue
1)工程化和脚手架
Vue CLI是Vue官方提供的一个全局命令工具,可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
好处:开箱即用,零配置;内置babel等工具;标准化;
使用步骤:
①全局安装一次:
yarn global add @vue/cli
或者npm i @vue/cli -g
②查看Vue版本:vue --version
③创建项目架子:vue create project-name
④启动项目:yarn serve
或者npm run serve
2)项目运行流程
(1)脚手架目录文件结构
(2)main.js
//main.js :文件的核心作用:导入APP.vue,基于APP.vue创建结构渲染index.html
//1、导入Vue核心包
import Vue from 'vue'
//2、导入App.vue根组件
import App from './App.vue'
//3、提示:当前处于什么环境(prod or dev)
Vue.config.productionTip = false
//4、Vue实例化,提供render方法->基于App.vue创建结构渲染index.html
new Vue({
//el:'#app',作用:和$mount('#app')作用一致,用于指定vue所管理的容器
//render:h=>h(App)等价于以下结构
render:(createElement)=>{
return createElement(App)
}
}).$mount('#app')
3)组件化和根组件
(1)组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。好处是便于维护,利于复用,提升开发效率。
(2)组件分类:普通组件、根组件
根组件:整个应用最上层的组件,包裹所有普通小组件。
(3)App.vue文件(单个组件)的三个组成部分:结构(tempate)、样式(style,可支持less,需要装包)、行为(script)
(4)让组件支持less:
①style标签,<style lang="less">
,开启less公共
②装包:yarn add less less-loader
4)普通组件的注册
(1)局部注册:只能在注册的组件内使用
①创建.vue文件(三个组成部分)
②在使用的组件
内导入并注册
使用:当成html标签使用,<组件名></组件名>
注意:组件命令规范,要是用大驼峰命名法,如HmHeader
(2)全局注册:所有组件内都能使用
①创建.vue文件(三个部分)
②在main.js
中进行注册
使用同局部组件
5)组件的三大组成部分(结构、样式、逻辑)
(1)scoped样式冲突
默认情况下,写在组件中的样式会全局生效
,因此很容易造成多个组件之间的样式冲突问题。
①全局样式:默认组件中的样式会作用到全局
②局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件
<style scoped>
</style>
scoped原理:
①给当前组件模板的所有元素,都会被添加上一个自定义属性data-v-hash值,以区分不同的组件
②css选择器后面,被自动处理,添加上属性选择器:div[data-v-hash值]
最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到。
(2)data是一个函数
一个组件的data选型必须是一个函数
,保证每个组件实例,维护独立的一份数据对象。
data(){
return{
count:20
}
}
7、组件通信
组件的数据是独立的,无法直接访问其他组件的数据,组件通信就是指组件与组件
之间的数据传递。
(1)组件关系的分类:父子关系、非父子关系
(2)组件通信解决方案:
(3)父子通信流程图
①父组件通过props
将数据传递给子组件
②子组件利用$emit
通知父组件修改更新
(4)什么是prop
Prop定义:组件上注册的一些自定义属性
Prop作用:向子组件传递数据
特点:可以传递任意数量的prop,可以传递任意类型的prop
- props校验:
为组件的prop指定验证要求,不符合要求,控制台就会有错误提示,可以帮助开发者快速发现错误。(类型校验、非空校验、默认值、自定义校验)
props:{
校验的属性名:类型//Number String Boolean...
required:true,//是否必填
default:默认值,//默认值
validator(value){
return 是否通过校验//自定义校验逻辑
}
}
(5)prop&data、单项数据流
共同点:都可以给组件提供数据
区别:
①data的数据是自己的,可以随便改
②prop的数据是外部的,不能直接改,要遵循单向数据流
单向数据流:父级prop的数据更新,会向下流动,影响子组件。
1)父传子
(1)实例
2)子传父
(1)实例
3)非父子
(1)event bus事件总线
作用:非父子组件之间,进行简易消息传递。(复杂场景使用Vuex)
(2)provide & inject
作用:跨层级共享数据
8、进阶语法
1)v-model
(1)v-model原理
原理:v-model本质上是一个语法糖。例如应用在输入框上,就是value属性和input事件的合写。
作用:提供数据的双向绑定
①数据变,视图跟着变:value
②视图变,数据跟着变@input
注意:$event
用于在模板中,获取事件的形参
<template>
<div id="app">
<input v-model="msg" type="text">
<input :value="msg" @input="msg=$event.target.value" type="text">
</div>
</template>
(2)表单类组件封装
实现子组件和父组件数据的双向绑定
(3)v-model简化代码
实现子组件和父组件数据双向绑定
2) sync修饰符
作用:实现子组件与父组件数据的双向绑定,简化代码
特点:prop属性名可以自定义,非固定为value
场景:封装弹框类的基础组件,visible属性 true显示 false隐藏
本质:就是:属性名
和@update:属性名
合写
//父组件
<BaseDialog :visible.sync="isShow"/>
<BaseDialog :visible="isShow" @update:visible="isShow = $event"/>
//子组件
props:{
visible:Boolean
},
this.$emit('update:visible',false)
3)ref和$ref
作用:利用ref和$ref可以用于获取dom元素或组件实例
特点:查找范围是当前组件内(更精确稳定)
(1)获取dom
①目标标签-添加ref属性
<div ref="chartRef">我是渲染图表的容器</div>
②恰当的时机,通过this.$refs.xxx
获取目标标签
mounted(){
console.log(this.$refs.chartRef)
}
使用querySelector
查找的是整个页面
(2)获取组件
①目标组件-添加ref属性
<BaseForm ref=baseForm"></BaseForm>
②恰当时机,通过this.$refs.xxx
获取目标组件,就可以调用组件对象里面的方法
this.$refs.baseForm.组件方法()
4、$nextTick
Vue异步更新DOM的,想要在DOM更新完成之后做某事,可以使用$nextTick
。
$nextTick
:等DOM更新后,才会触发执行此方法里的函数体
语法:this.$nextTick(函数体)
this.$nextTick(()=>{
this.$refs.inp.focus()
})
9、自定义指令
自定义指令:自己定义的指令,可以封装一些dom操作,扩展额外功能。
10、插槽
默认插槽、具名插槽
11、路由的基本使用
单页应用程序:SPA-Single Page Application
所有功能在一个html页面上实现,如网易云音乐
Vue中的路由:路径和组件的映射关系
1)VueRouter的介绍
作用:修改地址栏路径时,切换显示匹配的组件
说明:是Vue官方的一个路由插件,是一个第三方包
2)VueRouter的使用(5+2)
(1)5个基础步骤(固定)
①下载VueRouter模块到当前工程,vue2对应的版本是3.6.5
yarn add [email protected]
②main.js引入
import VueRouter from 'vue-router'
③安装注册
Vue.use(VueRouter)
④创建路由对象
const router = new VueRouter()
⑤注入,将路由对象注入到new Vue实例中,建立关联
new Vue({
render: h=>h(App),
router
}).$mount('#app')
(2)2个核心步骤
①创建需要的组件(views目录),在main.js中配置路由规则
//在Vue..use(VueRouter);后
import ViewsParent from "@/views/ViewsParent.vue";
import viewsDialog from "@/views/ViewsDialog.vue";
const router = new VueRouter({
routes: [
{ path: "/parent", component: ViewsParent },
{ path: "/dialog", component: viewsDialog },
],
});
②配置导航,在App.vue中配置路由出口(路由匹配的组件显示的位置)
<div id="app">
<a href="#/parent">parent</a><br />
<a href="#/dialog">dialog</a>
<router-view></router-view>
</div>
3)组件存放目录问题
组件分类:.vue文件分2类,页面组件&复用组件
注意:都是.vue文件(本质无区别)
分类开来更易维护
①src/views文件夹:页面组件,用于页面展示,配合路由用
②src/components文件:复用组件,用于展示数据,常用于复用
12、路由进阶
1)路由模块封装
目标:将路由模块抽离出来。好处:拆分模块,利于维护。
新建router目录,在该目录下新建index.js,将main.js中有关路由的内容抽离到index.js中
main.js
点击查看代码
//main.js
import router from "@/router/index.js";
new Vue({
render: (h) => h(App),
router,
}).$mount("#app");
router/index.js
点击查看代码
//router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import ViewsParent from "@/views/ViewsParent.vue";
import viewsDialog from "@/views/ViewsDialog.vue";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{ path: "/parent", component: ViewsParent },
{ path: "/dialog", component: viewsDialog },
],
});
export default router;
2)声明式导航
(1)导航链接
- vue-router提供了一个全局组件router-link(取代a标签)
①能跳转,配置to属性指定路径(必须)。本质还是a标签,to无需#
②能高亮,默认就会提供高亮类名,可以直接设置高亮样式
<router-link to="/find">发现</router-link>
//取代a
<a href="#/find">发现</a>
- 说明:
router-link自动给当前导航添加了两个高亮类名router-link-exact-active、router-link-active
①router-link-active模糊匹配:to="/my"可以匹配/my、/my/a等
②router-link-exact-active精确匹配:to="/my"仅可以匹配/my
- 定制声明式导航的两个高亮类名:
const router=new VueRouter({
router:[...],
linkActiveClass:"类名1",
linkExactActiveClass:"类名2"
})
(2)跳转传参
目标:在跳转路由时,进行传值
①查询参数传参(适合传多个参数):
- 配置导航链接:
to="/path"?参数名=值
- 对应页面组件接收传递过来的值:
$route.query.参数名
②动态路由传参(传单个参数比较方便):
- 配置动态路由:
const router=new VueRouter({
routes:[
...,
{
path:'/search/:words',
component:Search
}
]
})
- 配置导航链接:
to="/path/参数值"
- 对应页面组件接收传递过来的值:
$route.params.参数名
(3)动态路由参数可选符
/search/:words
表示,必须要传参数,如果不传参数,也希望匹配,可以加个可选符“?
”
const router=new VueRouter({
routes:[
...,
{
path:'/search/:words?',
component:Search
}
]
})
(4)路由重定向
问题 :网页打开,url默认是/路径,未匹配到组件时,会出现空白。
说明:重定向->匹配path后,强制跳转path路径
语法:{path:匹配路径,redirect:重定向到的路径}
const router=new VueRouter({
routes:[
{path:'/',redirect:'/'}
]
})
(5)Vue路由-404
作用:当路径找不到匹配时,给个提示页面
位置:配在路由最后
- 语法:
path:"*"
(任意路径)-前面不匹配就命中最后这个
const router=new VueRouter({
routes:[
{path:'*',component:NoFound}
]
})
(6)Vue路由-模式设置
问题:路由的路径看起来不自然,有
#
,能否切成真正路径形式
①hash路由(默认):http://localhost:8080/#/home
②history路由(常用):http://localhost:8080/home (上线需要服务器支持)
const router=new VueRouter({
routes,
mode:"history"
})
3)编程式导航
即用JS代码来进行跳转
(1)基本跳转
①path路径跳转(简易方便)
this.$router.push("路由路径")
this.$router.push({
path:'路由路径'
})
②name命名路由跳转(适合path路径长的场景)
//使用
this.$router.push({
name:'路由名'
})
//定义
const router=new VueRouter({
routes:[
{
name:'路由名',
path:'/path/xxxx',
component:XXXX
}
]
})
(2)跳转传参
两种传参方式:查询参数传参+动态路由传参,
上面两种跳转(path路径跳转、name命名路由跳转)方式,对于这两种传参方式都支持。
①path路径跳转传参
查询参数传参:
this.$router.push("/路径?参数名1=参数值")
this.$router.push({
path:'/路径',
query:{
参数名1:'参数值1'
}
})
- 对应页面组件接收传递过来的值:
$route.query.参数名
动态路由传参:
//先配置了动态路由
this.$router.push("/路径/参数值")
this.$router.push({
path:'/路径/参数值'
})
对应页面组件接收传递过来的值:$route.params.参数名
②name命名路由跳转传参
查询参数传参:
this.$router.push({
name:'路由名',
query:{
参数名1:'参数值1'
}
})
- 对应页面组件接收传递过来的值:
$route.query.参数名
动态路由传参:
//先配置了动态路由
this.$router.push({
name:'路由名',
params:{
参数名1:'参数值1'
}
})
- 对应页面组件接收传递过来的值:
$route.params.参数名
13、ESLint
//settings.json
{
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"editor.formatOnSave": false
}