vue
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue的基础原理:拦截
利用了Object.definedProperty方法进行拦截
var obox=document.getElementById("box");
Object.defineProperty(obj,"myname",{
//获取元素则执行
get(){
return obox.innerHTML
},
//修改元素则执行
set(value){
console.log("set",value)
obox.innerHTML=value
}
})
注意:vue3的变化
Object.defineProperty有以下缺点。
1、无法监听es6的Set、Map变化;
2、无法监听Class类型的数据;
3、属性的新加或者删除也无法监听;
4、数组元素的增加和删除也无法监听。
针对Object.defineProperty的缺点,ES6Proxy都能够完美得解决,它唯一的缺点就是,对IE不友好,所以vue3在检测到如果是使用IE的情况下(没错,IE11都不支持Proxy)
模板语法
切换样式:
<style>
.red{
background-color: red;
}
.yellow{
background-color: yellow;
}
</style>
</head>
<body>
<div id="box">
{{myname}}-{{myage}}
<div :class="isColor?'red':'yellow'">换背景颜色</div>
<button @click="handleChange()">change</button>
</div>
<script>
new Vue({
el:"#box",
data:{
myname:"xiaoming",
myage:12,
isColor:true
},
methods:{
handleChange(){
this.myname="hong",
this.myage=100
this.isColor=!this.isColor
}
}
})
</script>
- 表达式
指令:是带有v-前缀的特殊属性
v-bind 动态绑定属性
v-if 动态创建/删除,用来控制切换元素是否显示或隐藏类似if,还有v-else,v-else-if一般情况下一起使用
v-show 动态显示/隐藏
v-on 绑定事件
v-for 遍历,用来渲染列表,语法:v-for=“(item,index) in/of data”
v-model 双向绑定表单
v-html 针对纯HTML,将标签元素的效果展示。
缩写:
v-bind:src ->:src
v-on:click ->@click
todolist
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../code/lib/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" v-model="mytext"/>
<button @click="handleAdd()"></button>
<ul v-show="datalist.length">
<li v-for="(data,index) in datalist">
{{data}}
<button @click="handleDel(index)">del</button>
</li>
</ul>
<div v-show="!detalist.length">daiban</div>
</div>
<script>
var vm= new Vue({
el:"#box",
data:{
datalist:["111","222","333"],
mytext:"aaa"
},
methods:{
handleAdd(){
this.datalist.push(this.mytext)
this.mytext=""
},
handleDel(index){
this.datalist.splice(index,1)
}
}
})
</script>
</body>
</html>
点击变色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../code/lib/vue.js"></script>
<style>
.active{
background-color: red;
}
</style>
</head>
<body>
<div id="box">
<ul>
<li v-for="(data,index) in datalist" :class="current===index?'active':''" @click="handleClick(index)">
{{data}}
</li>
</ul>
</div>
<script>
new Vue({
el:"#box",
data:{
datalist:["1","2","3"],
current:0
},
methods:{
handleClick(index){
this.current=index
}
}
})
</script>
</body>
</html>
class与style
- vue2
不支持动态增加属性的拦截
解决方案:Vue.set(obj,属性,true) - Vue3
支持动态增加属性的拦截
Vue3语法:Vue.createApp(obj).mout("#box") || Vue.createApp({ }).mout("#box")
列表渲染
列表的渲染一般情况下,基本原理是使用了虚拟建立的DOM节点
- key
跟踪每一个节点,从而重用和重排现有元素,减少空间时间浪费
一般创建列表是建议都加上key值:id , data.id - 数组更新检测
a.使用以下方法操作数组,可以检测变动
push()、 pop() 、shift()、 unshift、 splice()、sort() 、reverse()
b.filter(),concat()和 slice() ,map),新数组替换旧数组
c.能检测以下变动的数组
vm.items[indexOfltem]=newValue
- 解决
(1)Vue.set(example1.items, indexOfltem,newValue)
(2)splice
- 应用:显示过滤结果
事件处理
(1)监听事件-直接触发代码
(2)方法事件处理器-写函数名handleClick
(3)内联处理器方法-执行函数表达式handleClick($event) $event事件对象
(4)事件修饰符https://cn.vuejs.org/v2/guide/events.html
.stop 防止事件冒泡,加在子元素上
.prevent
.capture
.self 防止事件冒泡,加在父元素上
.once
计算属性和监听器(watch)
- data -> 状态,被拦截。
- 方法 ->事件绑定,逻辑运算,可以不用return,没有缓存,每次相同调用,都要执行一次
- 计算属性(重视结果)->解决模板过重的问题,必须有return,只求结果,有缓存,同步,每次相同调用,只执行一次
- watch(重视过程),监听一个值的改变。不用返回值,异步同步。
fetch
用法:
fetch("...").then(res=>res.json()).then(res=>...)
get url路径 ?name=...&age=...
post body请求体
(1) x-www-formurlencoded,name=...&age=... (2json, ·{"name":"..."&...}·)
axios
先引入相关文件
语法:
axios.post("***","name=...&age=...")
axios.post("***",{name:"..."&...})
axios.get("")
工厂过滤器
<img :src="item.img | imgFilter1 | imgFilter2">
<script>
Vue.filter("imgFilter1",(url)=>{
return url.replace('w.h/','')})
Vue.filter("imgFilter2",(url)=>{
return url+'@......'})
</script>
组件
1.起名字:js驼峰,html 链接符-
2.dom片段 没有代码提示 没有高亮显示-vue单文件组件解决
3.css 只能写成 行内。-vue单文件组件解决
4. template 包含一个根节点
5.组件是孤岛,无法【直接】访问外面的组件的状态或者方法。-间接的组件信来交流。
6.自定义的组件 data 必须是一个函数,
7.所有的组件都在一起, 太乱了 — vue单文件组件解决
语法:
//全局定义
Vue.component("navbar",{
template:`自定义组件元素及样式,不能并列组件,只能嵌套`,
//自定义的属性及方法,只能在封装块中定义。
methods:{
自定义组件绑定的方法
},
//data必须是函数
data(){}
})
//局部定义
Vue.component("navbar",{
template:`自定义组件元素及样式+子定义组件元素`,
//自定义的属性及方法,只能在封装块中定义。
methods:{
自定义组件绑定的方法
},
//data必须是函数
data(){}
components:{
自定义子组件,创建语法与前面一致。
}
})
父传子
<div>
<navbar myname="..." :myright="..."></navbar>
<div>
<script>
Vue.component("navbar",{
//第一种方式:props:["myname","myright"],//接受定义的属性
//第二种
props:{
myname:{
type:String,
default:""
},
myright:{
type:Boolean,
default:true
}
}
template:`自定义组件元素及样式,不能并列组件,只能嵌套`,
//自定义的属性及方法,只能在封装块中定义。
methods:{
自定义组件绑定的方法
},
//data必须是函数
data(){}
})
</script>
子传父
在父组件的子组件上定义一个方法用
@myevent(方法名)="函数"
,挂载子组件传递过来的参数,然后在子组件中,通过this.$emit("方法名",数据)
来传送
在调用方法时,
若在子组件传入数据this.$emit("方法名",data(数据))
会默认传递一个形参
方法名(data){console.log(data)}
,并接受
中间人模式(兄弟传值或复杂关系传值)
第一种方法:通过本身先传值给父级元素,父级组件再将数据传入另一个等级组件种,再然后通过关系一步步传入。
第二种方法:利用ref直接绑定DOM,拿到的就是dom对象,绑定组件,就是组件对象,接着直接通过
this.$ref.属性名
直接获取,并传入,但是不推荐大量使用。
bus
订阅发布模式
var bus=new Vue()
中央事件总线:
事件监视:bus.$on("自定义事件名称",要获取的数据)
->接收数据,给接受数据的组件绑定,一般在mounted中
事件发送:bus.$emit("自定义事件名称",接收数据想要的数据)
->发送数据
动态组件
<component>
元素,动态地绑定多个组件到它的is属性
//若变量符合条件则显示相应的组件
<component is="wihch(变量)"></component>
<keep-alive>
保留状态,避免重新渲染
slot插槽
- 混合父组件的内容与子组件自己的模板–>内容分发
- 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../code/lib/vue.js"></script>
</head>
<body>
<div id="box">
<navbar>
<button @click="isShow=!isShow">click</button>//对应slot
</navbar>
<slidebar v-show="isShow"></slidebar>
</div>
<script>
Vue.component("navbar",{
template:
`
<div>
<slot></slot>
</div>
`
})
Vue.component("slidebar",{
template:
`
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
`
})
new Vue({
el:"#box",
data:{
isShow:false
}
})
</script>
</body>
</html>
注意:v-slot只能添加在template上
trsnsition过渡
多元素过渡时,相同等级及相同标签名的,须要添加key值
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../code/lib/vue.js"></script>
<style>
.a-enter-active{
animation: ccc 1s ;
}
.a-leave-active{
animation: ccc 1s reverse;
}
@keyframes ccc {
0%{
opacity: 0;
transform: translateX(100px);
}
100%{
opacity: 1;
transform: translateX(0px);
}
}
</style>
</head>
<body>
<div id="box">
<input type="text" v-model="mytext"/>
<button @click="handleAdd()">add</button>
//多个组件(列表过渡)
<transition-group name="a" tag="ul" v-show="datalist" mode="out-in\(in-out)"显示方式:先加后删或相反>
<li v-for="(data,index) in datalist" :key="data">
{{data}}
<button @click="handleDel(index)">del</button>
</li>
</transition-group>
<div v-show="!datalist.length">daiban</div>
</div>
<script>
var vm= new Vue({
el:"#box",
data:{
datalist:["111","222","333"],
mytext:"aaa"
},
methods:{
handleAdd(){
this.datalist.push(this.mytext)
this.mytext=""
},
handleDel(index){
this.datalist.splice(index,1)
}
}
})
</script>
</body>
</html>
虚拟dom的diff方式
生命周期
swiper学习
https://www.swiper.com.cn/
Vue3组件
var app=Vue.createApp()
//定义新组件
Vue.component("couter",{
//data必须声明为一个返回一个初始数据对象的函数
data:function(){
return ...
},
template:`组件布局`
})
指令
- 自定义指令
<div id="box">
<div v-hello="'red'">11111</div>
</div>
<script>
Vue.directive("hello",{
inserted(el,binding){
console.log(binding)
el.style.backgroundColor=binding.value
//el:插入元素节点
//binding节点的属性
//binding.value为red
}
})
new Vue({
el:"#box",
data:{
}
})
})
- 钩子函数
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新(详细的钩子函数参数见下)。
- componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
- nextTick
比updated执行还要晚,只执行一次
一般用在轮播插入最后一个元素后再进行,但是不建议,易出现bug
单文件组件
vue-cli
- npm install -g @vue/cli (一次安装)
- +vue create myapp
- npm run serve 开发环境构建
- npm run build 生产环境构建
- npm run lint 代码检测工具
- style标签 加上scoped属性,css局部生效 style标签 加上
lang=\"scss\"
,支持scss
proxy代理
在vue.config.js中配置
反向代理
devServer:{
port: ,//
proxy:{
'/xiao':{
target:'htpp://...',
changeOrigin:true,
pathRewrite:{
'^/xiao':''//将不同的数据,但是名字重复的重新设置名子的,重新改为原来的样子。
}
}
}
}
路由器
- (1)hash路由 > location.hash 切换
window.onhashchange 监听路径的切换 - (2)history路由> history.pushState 切换
window.onpopstate 监听路径的切换
<router-view></router-view>//路由容器
- router/index.js
Vue.use(VueRouter)// 注册路由插件
// 配置表
const routes = [
{
path: '/films',
component: Films,
//嵌套路由
children:[
{
path:'/films/nowplaying',
component:Nowplaying
}
]
},
{
path:'/center',
component:()=>import('@/views/Center'),//懒加载,防止在主页时加载时间过长
meta:{
isrequired:true
}
}
{
path: '/cinemas',
component: Cinemas
},
{
path: '/center',
component: Center
},
// 重定向
{
path: '*',
redirect: '/films'
},
{
name: 'xiaoDetail', // 命名路由
path: '/detail:id', // 动态路由
component: Detail
}
导航
- 声明式导航
<!-- 声明式导航 -->
<!--vue 4 写法 -->
<router-link to="/films" custom v-slot="{navigate,isActive}" >
<li @click="navigate" :class="isActive?'xiaoming':''">电影</li>
</router-link>
<!--vue 3之前 及3 写法-->
<router-link to="/cinemas" active-class="xiaoming" tag="li">影院</router-link>
- 编程式导航
<template>
<div>
nowplaying
<ul>
<li v-for="data in datalist" :key="data" @click="handleChangePage(data)">
{{data}}
</li>
</ul>
</div>
</template>
export default {
data () {
return {
datalist: ['111', '222', '333']
}
},
methods: {
// 编程式导航
handleChangePage (id) {
// 1.通过路径跳转
// this.$router.push(`/detail/${id}`)
// 2.通过命名路由跳转
this.$router.push({
name: 'xiaoDetail',
params: {
id
}
})
},
//全局式拦截
router.beforeEach((to,from,next)=>{
if(to.meta.isrequired)
{
//判断是否含有token
if(localStorage.getItem('token'))
{
next()//有就跳转页面
}else
{
next('/login')//没有就拦截
}
}else
{
next()
}
})
}
}
rem布局复习
document.documentElement.style.fontSize=document.documentElement.clientWidth/(设计稿宽度)*100+'px'
axios初次封装
//内封装http.js
import axios from 'axios'
const http =axios.create({
baseURL:'',
timeout:10000,
headers:{
}
})
export default http
//外使用,应用在不同的组件文件中
import http form 'axios文件地址'
export default{
data(){
return {
}
},
mouted(){
http({
url:'获取内容的地址',
headers:{
}
}).then(res=>{})
}
}
axios拦截
本课程主要用该方式,对加载动画进行添加和删除。
// Add a request interceptor --在发送请求之前拦截 ->showLoading
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor --在成功后拦截 -- hideLoading
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
饿了吗组件库和vant组件库
https://element.eleme.cn/#/zh-CN
http://vant3.uihtm.com/#/zh-CN
Vuex
Vuex是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
//新创建一个store文件夹,其中放入带有vuex的index.js的文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//state公共状态,传入公共数据
state:{
},
//统一管理,被devtools 记录状态的修改
//只能支持同步
//是对状态的追踪,而非改变
//改变状态在methods中进行
mutations:{
},
//Action 类似于 mutation,不同在于:
//Action 提交的是 mutation,而不是直接变更状态。
//Action 可以包含任意异步操作。
actions:{
}
})
- 可以用辅助函数来减少重复的this.$store.—
mapState、mapActions、mapMutations
//在需要使用的组件文件中引入
import {mapState、mapActions、mapMutations} from 'vuex'
export default {
component:{
...mapState[{'title'}]//与this.$store.title一样
},
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
}
}
git
基础使用方法 -->git–菜鸟教程
经典web服务器nginx介绍
Nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器;同时也是一个IMAP、POP3、SMTP代理服务器;Nginx可以作为一个HTTP服务器进行网站的发布处理,另外Nginx可以作为反向代理进行负载均衡的实现。
-
(1)正向代理
正向代理最大的特点是客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式屏蔽或者隐藏了真实客户端信息。 -
(2) 反向代理\n\n客户端是无感知代理的存在的,反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。因为客户端不需要任何配置就可以访问。
反向代理,“它代理的是服务端”,主要用于服务器集群分布式部署的情况下,反向代理隐藏了服务器的信息。 -
nginx的基础配置(代理等)
nginx -c kerwin.conf 加载kerwin.conf 并启动服务器
nginx -s
{
stop — fast shutdown
reload — reloading the configuration file(每次修改完kerwin.conf后 ,都通过此方法 重新加载一次)
}
静态文件serve
location / {
root html;//是当前文件夹下有个html文件夹
index index.html index.html
}
location /frontend {
root html ;
#只要加载localhost/frontend路径 那么就会从 html/frontend/路径提供文件服务
}
下面四种情况分别用http://localhost/proxy/test.html 进行访问。
// 注意 /proxy/ 后面的/ 需要加上
(1)location /proxy/ {
proxy_pass http://127.0.0.1:8000/;
}
会被代理到http://127.0.0.1:8000/test.html 这个url
(2)相对于第一种,最后少一个 /
location /proxy/ {
proxy_pass http://127.0.0.1:8000;
}
会被代理到http://127.0.0.1:8000/proxy/test.html 这个url
(3)location /proxy/ {
proxy_pass http://127.0.0.1:8000/xiaoming/;
}
会被代理到http://127.0.0.1:8000/xiaoming/test.html 这个url。
(4)相对于第三种,最后少一个 / :
location /proxy/ {
proxy_pass http://127.0.0.1:8000/xiaoming;
}
会被代理到http://127.0.0.1:8000/xiaomingtest.html 这个url
- (4)将nginx部署在线上作为webserver serve 静态资源, 并反向代理node服务
Vue3
- 创建
const app =Vue.createapp('...')
const helloApp={
data(){
return{
message:{
}
}
}
}
Vue.createApp('...').mount('#hello-vue')//用mount进行挂载
- reactive
reactive 是 Vue3 中提供的实现响应式数据的方法。
在 Vue2 中响应式数据是通过 defineProperty 来实现的,
在 Vue3 中响应式数据是通过 ES6 的 Proxy来实现的。
reactive 参数必须是对象 (json / arr)
如果给 reactive 传递了其它对象
默认情况下,修改对象无法实现界面的数据绑定更新。
如果需要更新,需要进行重新赋值。(即不允许直接操作数据,需要放个新的数据来替代原数据)
在 reactive 使用基本类型参数
基本类型(数字、字符串、布尔值)在 reactive 中无法被创建成 proxy 对象,也就无法实现监听。
ref
ref函数接受一个值并返回一个响应式的、可变的Ref对象。Ref对象只有一个.value属性值。
- 第一种实现,通过reactive方法直接实现
function ref(intialValue){
return reactive({value:intialValue})
}
- 对象访问器
Vue3中ref使用了一个概念对象访问器,这属于JavaScript里计算属性的概念。
toref
toRef用来给抽离响应式对象中的某一个属性,并把该属性包裹成ref对象,使其和原对象产生链接
toRef是做的一种引用关系,修改msg2的值,会影响对象msg,但视图不会发生变化
setup(){
let msg = { name: 'zs', age: 16 }
let msg2 = toRef(msg, 'name')
console.log(msg2.value) // zs
function change2() {
msg2.value = 'ww'
console.log(msg, msg2.value) // {name: "ww", age: 16} ww
//此时 msg.ww 数据变了 但是视图上的是不会变的
}
change2()
return { msg2,change2 }
}
3. toRefs的使用
toRefs用来把响应式对象转换成普通对象,把对象中的每一个属性,包裹成ref对象
toRefs就是toRef的升级版,只是toRefs是把响应式对象进行转换,其余的特性和toRef无二
setup(){
let msg = { name: 'zs', age: 16 }
let msg3 = toRefs(msg)
console.log(msg) // { name:ref, age:ref } ref代指ref对象
function change3() {
msg3.name.value = 'zl'
msg3.age.value = 20
console.log(msg, msg3) // {name: "zl", age: 20} { name:ref, age:ref }
}
change3()
return { msg3, change3 }
}
- ref、toRef、toRefs 都可以将某个对象中的属性变成响应式数据
- ref的本质是拷贝,修改响应式数据,不会影响到原始数据,视图会更新
- toRef、toRefs的本质是引用,修改响应式数据,会影响到原始数据,视图会更新
- toRef 一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
- toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行
Vue3的生命周期
一、Vue3中的生命周期
1、setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method
2、onBeforeMount() : 组件挂载到节点上之前执行的函数;
3、onMounted() : 组件挂载完成后执行的函数;
4、onBeforeUpdate(): 组件更新之前执行的函数;
5、onUpdated(): 组件更新完成之后执行的函数;
6、onBeforeUnmount(): 组件卸载之前执行的函数;
7、onUnmounted(): 组件卸载完成后执行的函数;
8、onActivated(): 被包含在 <keep-alive>
中的组件,会多出两个生命周期钩子函数,被激活时执行;
9、onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;
10、onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。
vue2 -------> vue3
beforeCreate --------> setup(()=>{})
created --------> setup(()=>{})
beforeMount --------> onBeforeMount(()=>{})
mounted --------> onMounted(()=>{})
beforeUpdate --------> onBeforeUpdate(()=>{})
updated --------> onUpdated(()=>{})
beforeDestroy --------> onBeforeUnmount(()=>{})
destroyed --------> onUnmounted(()=>{})
activated --------> onActivated(()=>{})
deactivated --------> onDeactivated(()=>{})
errorCaptured --------> onErrorCaptured(()=>{})
watch
- 监听整个对象
其第一个参数是直接传入要监听的对象。当监听整个对象时,只要这个对象有任何修改,那么就会触发 watch 方法。无论是其子属性变更(如 demo.name),还是孙属性变更(如 demo.soulmate.name)…,都是会触发 watch 方法的。
watch(demo, (newValue, oldValue) => {
console.log('watch 已触发', newValue)
})
- 监听对象中的某个属性
// 监听demo对象的name属性
watch(() => demo.name, (newValue, oldValue) => {
console.log('watch 已触发', newValue)
})
如上代码,监听 demo 对象的 name 属性,那么只有当 demo 对象的 name 属性发生变更时,才会触发 watch 方法,其他属性变更不会触发 watch 方法。
- 只监听对象的子属性
watch(() => ({ ...demo }), (newValue, oldValue) => {
console.log('watch 已触发', newValue)
})
- 监听对象的所有属性
watch(() => demo, (newValue, oldValue) => {
console.log('watch 已触发', newValue)
}, { deep: true })
这个相当于监听整个对象(效果与上面的第一种相同)。但是实现方式与上面第一种是不一样的,这里我们可以看到,第一个参数是箭头函数,并且还多了第三个参数 { deep: true }。当加上了第三个参数 { deep: true },那么就不仅仅是监听对象的子属性了,它还会监听 孙属性,曾孙属性 …
通常要实现监听对象的所有属性,我们都会采用上面第一种方法,原因无他,第一种编码简单,第一个参数直接传入 demo 即可。
- 组合监听
watch([() => demo.name, nums], ([newName, newNums], [oldName, oldNums]) => {
console.log('watch 已触发: name', newName)
console.log('watch 已触发: nums', newNums)
})
同时监听 demo 对象的 name 属性,和基础类型 nums,只要他们其中任何一个发生变更,那么就触发 watch 方法。
hooks
本质而言,hook就是一个函数,只不过hook是把 setup组合函数之中的 组件api(ref、reactive、conputed、watch、生命周期函数)等进行了封装抽离代码(公共代码,公共组件等),这样使得代码更加简洁
hook 类似于 vue2之中的 mixin