Vue官网文档: Vue.js
Vue介绍:
Vue (读音 /vjuː/) 是一套用于 构建用户界面(数据渲染到页面) 的渐进式 框架
库(Library):
本质:一些函数的集合。每次调用函数(把库当成工具使用),实现一个特定的功能。
例如:axios、moment
框架(Framework):
由很多个库组成的一套完整的解决方案
例如: vue、react
库和框架区别:
(1)如果库是一台电脑的某一个零部件,那么框架就是一整台组装好的电脑。
(2)使用库:自由
使用框架:按照框架的规则写代码,限制多,但功能更强大,可提升开发效率
Vue 是 MVVM设计模式 的框架
MVVM设计模式:一种软件架构模式,决定了写代码的方式。
M:model数据模型(ajax获取到的数据)
V:view视图(页面)
VM:ViewModel 视图模型(vue实例)
MVVM 通过
数据双向绑定
让数据自动地双向同步在vue中 不在需要操作DOM 数据驱动视图 想着如何操作数据!!
Vue基本使用
第三方框架通用的使用步骤
1.导包
2.写HTML结构
3.js中初始化配置
<!-- 1.导包 -->
<script src="./vue.js"></script>
<body>
<!-- 2.HTML结构 -->
<div id="app">
{{ name }}
{{ age }}
</div>
<script>
/* 3.初始化vue实例 */
/*
(1)Vue:是导入vue.js之后得到的一个全局构造函数
(2)app:是调用Vue构造函数 创建一个vue实例对象
(3)el: element 用来设置vue实例的挂载点(将数据渲染到哪个元素身上)
(4)data: 要渲染的数据 (数据驱动:vue会根据data中的数据,自动渲染页面(无需DOM操作))
*/
let app = new Vue({
el: '#app',
data: {
name:'张三',
age:18,
}
})
</script>
</body>
el:挂载点
作用 : 告诉vue,数据渲染到哪个元素上
注意点:
(1)挂载点可以使用 id选择器(唯一性 )(vue推荐) 类选择器 标签选择器等
(2)如果选择器选中了多个元素,只会选择第一个元素
(3)挂载点不能设置为html和body标签 (程序报错)
插值表达式
作用:告诉vue,你想把数据渲染在什么位置
语法:
{{ 表达式 }}
插值表达式
注意点
:(1) 使用的数据在 data 中要存在
(2) 不支持分支和循环,支持三元运算符
(3) 不能写在元素行内
指令
作用:给标签新增一些功能
本质:自定义属性
语法 :
指令名=“指令值”
v-text 指令
作用: 设置元素的文本 innerText
与插值表达式区别:
v-text 设置元素的文本,如果元素有文本,则会覆盖现有的文本
{{ }} 只会替换当前位置文本
v-html 指令
作用: 设置元素的innerHTM
v-on 指令
作用: 给元素绑定事件
语法:
标准语法: v-on:事件名 = "方法名"
简洁语法: @事件名 = "方法名"注意点
事件名就是原生事件名去掉on
事件方法定义在vue实例的methods对象中
v-on 指令 事件修饰符
语法: @事件名.修饰符 = "方法名"
绑定enter键事件: @事件名.enter 例:@keydown.enter="doEnter"
阻止事件冒泡: @事件名.stop
阻止事件默认行为: @事件名.prevent
v-on 事件传参
1.vue中每一个事件方法都有一个默认参数 , 就是事件对象
2.如果主动给事件传参,则传递的参数 会 覆盖默认参数
3.如果希望同时传入
事件对象
+自定义参数
,则可以使用$event
v-on:click="doClick($event,自定义参数)"
vue事件方法中的this
(1) this指向 : vue实例
(2)vue事件方法中 访问data对象中的成员 : this.属性名
原因: vue会平铺data与methods成员到vue实例中
(3)注意点:
1.如果事件处理代码没有写到methods中,而是在行内则不需要this
2.如果在vue的methods中使用了箭头函数,则此时this会指向 window 不要使用箭头函数
v-bind指令
作用: 设置HTML标签属性的值
(默认情况下,
HTML属性
无法获取vue中的数据 ,如果希望HTML属性
也可以获取vue中的数 据,就可以使用v-bind指令
)语法:
标准语法: v-bind:原生属性名 = "属性值"
简洁语法: :原生属性名 = "属性值"例: v-bind:src="imagePath"
v-bind 样式绑定
v-bind:class="{ '类名': bool, '类名': bool ......}"
如果值为true 该类样式就会被应用在元素身上, false则不会
注意点:如果类名有 - ,则需要使用引号包起来
<button @click="changeClass">切换样式</button>
<div :class="{ greenBorder: true, 'blue-box': flag }"></div>
<div :style="{ width:width , height , 'background-color':bgc}"></div>
v-for指令
(1)作用:遍历数组,并重复生成对应长度的相同标签
(2)语法: v-for="item in 数组名"
遍历带下标: v-for="(item, index) in 数组名"
(3)注意: 这个指令写在哪一个元素身上,就重复生成哪一个元素应用:排他思想(下标)
v-model指令
作用 : 让 data数据 与 表单 建立双向绑定
表单的值发生变化, data数据也会变化
data数据发送变化,表单的值也会变化
注意点:
v-model只能用于表单元素
v-model绑定的数据要在data中声明
语法: v-model="变量名"
了解:双向绑定技术的底层原理是:js属性拦截
v-model修饰符
语法
v-model.lazy : 在change时触发而非inupt时(失去焦点或enter键的时候才会绑定数据)
v-model.number : 输入字符串转为有效的数字 (有效:能转数字就转,不能转就不转)
v-model.trim : 去掉字符串首尾空格
v-if指令
作用: 根据条件渲染数据
语法:
单分支: v-if="条件语句"
双分支: v-else
多分支: v-else-if="条件语句"注意点: v-else与v-else-if的前面 必须要有 v-if 或者 v-else-if
v-show 指令
作用: 设置元素的display属性值
语法: v-show="属性值"
属性值为true: 元素的display:block
属性值为false: 元素的display:nonev-show与v-if区别
v-if : 条件渲染。 如果不满足条件,则该元素不会添加到DOM树中
v-show: 显示与隐藏。 只是修改元素的display属性值
面试题v-if和v-show区别
1.v-if : 本质是在动态的创建 或者 删除元素节点
应用场景:如果是不用频繁切换, 要么显示, 要么隐藏的情况, 适合于用 v-if
v-if 是惰性的, 如果初始值为 false, 那么这些元素就直接不创建了, 节省一些初始渲染开销
2.v-show: 本质是在控制元素的 css 样式,
display: none;
应用场景:如果是频繁的切换显示隐藏, 用 v-show
v-if, 频繁切换会大量的创建和删除元素, 消耗性能
vue中key值
作用:
(1)让vue准确的识别DOM元素 (类似于给元素添加一个身份证)
(2)让vue强制更新DOM应用场景:
1 .使用v-if 切换元素
什么时候用key值 : 切换的元素dom结构一致
2. 使用v-for 渲染列表
什么时候用key值 :所有的v-for推荐全部加上key值
虚拟DOM
vue底层会把挂载点中的真实DOM结构,转变为虚拟DOM。
真实DOM :wdom对象, 一个对象里面有几百个属性
虚拟DOM :
本质是一个js对象
,只处理一些关键的属性。(其他的不处理)虚拟DOM的好处
提高DOM更新的性能, 不频繁操作真实DOM, 在内存中找到变化部分, 更新真实DOM
vue是如何更新渲染数据呢
虚拟DOM更新流程
(1)当数据更新之后,vue会使用diff算法进行新旧VNode对比
a. key值相同的元素考虑复用, key值不同的元素 强制更新
b. 如果父元素不同,则强制更新。父元素一致,则开始递归遍历子元素
c. 子元素如果相同就复用,不同就更新
(2)更新diff算法找到的不同的元素 (打补丁:边找边改)
diff算法
vue就地复用策略:Vue会尽可能的就地(同层级,同位置),对比虚拟dom,复用旧dom结构,进行差异化更新。
v-for指令使用key值几种情况
1. 没有key值 : 不复用,就地更新
2. key值是下标 : 不复用,就地更新( 设置下标和不设置,没区别。 默认就是参考下标)
3. key值是id : 复用相同的key,更新不同的key
总结: key值优先使用id , 没有id的话用下标
v-for更新检测
1.数组的方法分为两种
第一种: 会改变数组本身 (v-for会更新视图)
reverse()、sort()、splice()、push()、pop()、shift()、unshift()
第二种: 不会改变数组本身, 而是返回一个新数组 (v-for不会更新视图)
filter()、slice()、concat()、map()
2.总结 : 面试题:你在使用vue的时候,有没有遇到什么bug.你觉得vue有哪些不好的地方?
有遇到过。比如渲染数组的时候,数组有的方法不会改变原数组,就会导致页面视图不更新的情况。(有时候面试官可能会问你具体是那些方法,最好能回答几个出来)
也有的时候,直接修改数组的元素,结果页面视图也不更新。一般遇到这种情况,我要么想办法强制对数组进行重新赋值。 要么使用 vue官方提供的 $set() 方法对数组进行强制更新。
//把下标为1的元素改成66
// (1)直接用下标修改数组的元素,可能会导致视图不更新
// this.list[1] = 66
// (2)解决方案: 用vue官网提供的 vm.$set 强制更新视图
// 第一个参数:要更新的数组 第二个参数:要更新的下标 第三个参数:更新后的值
this.$set( this.list , 1 , 66 )
vue计算属性
作用: 解决模板语法的冗余问题
场景: 数组求和、全选、(某个数据需要经过复杂的计算才能得到)
语法:
computed:{
计算属性名(){
return 计算属性值
}
}
注意点
a. 计算属性虽然写起来是一个函数写法, 但是最终会被vue变成属性
b. 计算属性一定要写在computed对象中, 一定要有返回值return
计算属性缓存机制
a 第一次使用计算属性, vue执行一次计算属性。并且将 函数名和返回值 平铺到vue实例中变成属性
b 之后使用计算属性, vue不再执行这个函数,而是直接从缓存中读取
c 只有当计算属性内部的数据发生变化的时候才会重新执行一次这个函数,然后又放入缓存
vue计算属性的get 和set方法
1. 计算属性默认只能get读取,不能主动修改
2. 如果想要主动修改计算属性,就需要实现set方法
函数写法, 只要get读取
计算属性名() {}
对象写法,有get+set
计算属性:{ get() { return 值 }, set(val) { //val:要设置的值 } }
侦听器
作用 : 监听data中某一个数据变化
语法 :
watch:{
data属性名(newVal,oldVal){
//只要被侦听的属性变化了,就会执行这个函数
}
}
面试点 : 侦听器和计算属性区别
(1)计算属性有缓存机制,侦听器没有
(2)计算属性不支持异步操作, 侦听器支持异步操作
(3)计算属性是一个额外新增的属性, 侦听器只能侦听data中的属性
(4)计算属性有返回值return,侦听器不需要return
(5)计算属性可以监听多个数据变化(计算属性内部用到的数据变化了,就会执行计算 属性方法),侦听器只能侦听一个数据的变化。
深度侦听
作用 : 侦听引用类型变化
语法:
data属性:{
deep:true,
handler(newVal,oldVal){
}
}
普通侦听( 函数写法)
data属性() {}
深度侦听 (对象写法)
data属性:{ deep:true, handler(newVal,oldVal) {} }
vue-cli工具
(1)安装:打开终端小黑窗,输入命令 npm install -g @vue/cli
(2)检查有没有安装成功:
vue --version
(3)如果安装失败,清除npm缓存,再重新安装,清除缓存命令 npm cache clean -f
脚手架:指的
是
一个项目的目录结构
作用:
(1)生成规范的vue项目目录
(2)底层基于webpack, 将后缀名为 .vue 的文件 编译成浏览器可以识别的 html文件
创建vue项目 :
vue create 项目名称
(
项目名称不要有中文,也不要有大写字母)
运行项目的命令 :npm run serve
脚手架文件目录介绍
组件
(组件 == .vue文件 == vue实例 == 页面盒子(html+css+js一起) == 自定义html标签 )
本质:一个自定义的标签
作用:
复用
组成:(1)<template>标签,这里写组件的html结构
(2)<script>标签,这里写组件的js代码
(3)<style>标签,这里写组件的css代码
注意点: 一个template只能有一个子元素,vue会自动把<template>里面的根元素作为当前 组件(vue实例)的挂载点
组件名命名规范 :(1)短横线命名法 (2)大驼峰命名法(推荐)
注意:组件名不能与原生的HTML标签重名
注册局部组件
1.导入局部组件 : 在scrip标签中导入
import 组件名 from '组件路径'
2.注册组件 : 在export default里面写一个属性components
export default {
components: {
"标签名": 组件名
}
}
3.使用组件 : 像标签一样使用即可,组件可以理解为一个自定义标签
<组件名></组件名>
注册全局组件 : 在main.js文件中
1.导入组件
import 组件名 from '组件文件路径'
2.注册全局组件
Vue.component('标签名', 组件名)
3.一旦注册全局组件之后,可以在任何组件直接使用,并且不需要导入和挂载
css作用域scoped属性
1.默认情况下,如果父组件与子组件有相同的css选择器样式,则父组件的样式会覆盖子组件的样式
2.scoped属性作用 : 如果子组件与父组件有相同样式,则优先加载子组件自身的。如果没有则加载父组件的
3.scoped原理: 本质是给子组件添加一个唯一的行内自定义属性 data-v-xxx, 然后通过属性选择器来增加css权重
组件 name属性
作用: 给这个组件一个标识符,用于快速查找组件
特点: 必须是唯一,不能与其他组件name属性冲突,建议最好与组件名一致
name属性值不能是中文
组件通讯:父传子props
(1)父组件中:<子组件 属性名="属性值"></子组件>
(2)子组件中:添加props属性
(与data平级)
(prop中的属性不能有大写字母,不要使用驼峰命名。建议使用
-
作为分隔符 )props校验:验证传递的数据是否符合要求
props 提供了多种数据验证方案,例如:
基础的类型检查 Number
多个可能的类型 [String, Number]
必填项校验 required: true
默认值 default: 100
自定义验证函数
组件通讯:单向数据流
vue规定,
父组件
传递给子组件
的数据是只读的
.注意:
引用类型赋值本质是赋值地址
,如果在子组件修改则父组件也会变化。
组件通讯:子传父$emit
(1)子组件中发出 :this.$emit('事件名',事件对象)
(2)父组件中接收:<子组件 @事件名="函数名"></子组件>
v-model语法糖
作用:提供数据的双向绑定
v-model等价于 给一个input框提供了 :value属性以及 @input事件
场景:
父组件提供一个数据给子组件使用(父传子)
子组件又需要修改父组件传过来的这个数据,所以需要子传父把值传给父组件。
如果父传子的props值叫 value, 且 子传父触发的事件叫 input 。 那么这两个功能就可以使用v-model来简写
:value="msg" @input="$event.value" 与 v-model = "msg"
ref和$refs
ref作用:在vue中操作dom元素或组件vm实例
( vue不能直接操作dom,真的要操作也要按vue规定的语法来。(ref语法) )
(每个 vue 的组件实例上,都包含一个$refs 对象,里面存储着对应的DOM 元素或 组件的引用。 )
ref语法使用流程语法
(1)给标签添加自定义属性red :
<button ref="属性名"></button>
vue会自动把页面所有的ref属性,挂载到vue实例的$ref对象中
(2)通过
vm.$refs.属性名
获取该标签
一定要注意
: vue在mounted勾子中完成页面真实DOM渲染,所以最早能获取dom的就是mounted钩子
$nextTick(callback)
方法作用:会把 callback 回调推迟到下一个 DOM 更新周期之后执行。
(1) vue更新DOM是一个异步的过程。
(2) 异步代码需要等当前队列同步代码全部执行完毕之后才会执行
解决方案:
this.$nextTick(callback) : 会等组件的DOM刷新之后再来执行callback回调函数
dynamic 动态组件
动态组件概念: 让多个组件使用同一个挂载点,并动态切换
动态组件 与 v-if v-else
v-if v-else : 只是根据条件来决定渲染哪一个盒子,不能像组件那样复用。
动态组件:通过设置组件名,让一个挂载点可以切换不同的组件
自定义指令
本质 : 行内自定义属性
作用 : 给标签添加 vue没有的,额外的功能
局部注册:只能在当前组件使用
语法:
// inserted(el,binding) : 当指令被使用的时候会执行一次
// update(el,binding) : 当指令的值发生改变时触发
// el:指令所绑定的元素
// binding:一个对象,包含指令名、指令值等数据
directives: {
指令名: {
inserted(el,binding) {
},
update(el,binding) {
},}
},全局注册: 在main.js中注册,任何地方可用
语法:
Vue.directive("指令名", 指令对象)
slot匿名插槽
作用:
父
组件 传递 html结构
给子
组件使用:
(1)
子
组件:定义一个插槽<slot>默认显示</slot>
(2)
父
组件:传递结构:<子组件>父组件需要传递的结构</子组件>
slot 具名插槽
父组件
传递多个html结构
给子组件(给不同slot分发不同内容 )使用:
(1)子组件: <slot> 添加name属性 :
name="插槽名"
(2)父组件:使用
v-slot:插槽名
: 给指定的插槽传递结构
注意:这个v-slot指令必须要写在
<template>
标签中,否则会报错
<template>
标签本身不会被渲染,因此最终在页面是看不见的。 类似于divv-slot 指令 可以简写成
#
v-slot作用域插槽
作用域插槽语法如下:
(1)给子组件的<slot>添加一个自定义属性 :
<slot :属性名="属性值" ></slot>
(2)给父组件的<template>添加v-slot属性接收数据:
<template v-slot="对象名"> </template>
父组件使用子组件内部数据语法:
对象名.属性名
1.插槽与props的异同点
相同点: 都是父传子
不同点:
props: 传递的是数据
插槽:传递的是html结构
2.作用域插槽和$emit异同点
相同点:都是子传父
不同点:
$emit : 子传父的数据通过事件来接收
作用域插槽:子传父的数据是通过插槽v-slot接收 (子传父的数据,只能给 插槽用)
1.插槽作用:父组件 传递
html结构
给 子组件2.具名插槽作用:父组件 传递
多个html结构
给 子组件3.作用域插槽作用:父组件 给 子组件 传递插槽 时,可以使用子组件内部的数据
注意点
: 不要把具名插槽语法
和作用域插槽
语法搞混淆具名插槽:
<template v-slot:name值></slot>
作用域插槽:
<template v-slot="对象名"></slot>