Vue3 尚硅谷-张天禹

Vue列表过滤(过滤|排序不分家)-尚硅谷张天禹(笔记) 根据尚硅谷讲师张天禹老师VUe课程其中的一节Vue列表过滤整理的一篇笔记,学习记录,敬供参考。 阅读详情

一.使用vue-cli创建工程

Vue3简介

github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
1 源码的升级

  • 使用Proxy代替 defineProperty实现响应式
  • 重写虚拟DOM的实现和Tree-Shaking
    2 新的特性
    2.1Composition API(组合API):
  • setup配置
  • ref与reactive
  • watch与watchEffect
  • provide与inject
    2.2新的内置组件
  • Fragment
  • Teleport
  • Suspense
    2.3 其他改变
  • 新的周期钩子
  • data选项应始终被声明为一个函数
  • 移除keyCode支持作为v-on的修饰符

查看版本必须大于4.3

vue -v
//vue --version

创建vue项目

C:\Users\tianyu>cd Desktop
C:\Users\tianyu\Desktop>vue create vue3_test

cd vue3_test
yarn serve

使用vite创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网:https://vitejs.cn

在这里插入图片描述
优势

  1. 启动速度快,因为没有依赖包
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev

二.分析工程结构

脚手架安装失败原因

    1. npm原因:建议清理缓存
    1. 重装node.js
    1. 网络问题:配置淘宝镜像

vue2和vue3的结构区别

在这里插入图片描述

查看vue3里createApp里面的东西

在这里插入图片描述

关闭语法检查

vue.config.js

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  lintOnSave:false    //关闭语法检查
})

vue3特殊之处

vue里面可以没有跟组件

//vue里面可以没有跟组件
<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>

main.js

// createApp:引入的不在是Vue的构造函数,引入的是一个名为createApp的工厂函数(无需new,里面的方法直接调用,首字母小写)
import { createApp } from 'vue'
import App from './App.vue'

// 创建应用实例对象--app(类似于之前vue2中的vm,但app比vm"轻",因为去掉了一些不用的函数)
const app=createApp(App)
// 产看app里面的内容 
console.log('@@@@',app)
// 挂载
app.mount('#app')

// 1秒后卸载 app
setTimeout(()=>{  
    app.unmount('#app')
},1000)


// Vue2:
// const vm=new VueElement({
//     render:h=>h(App)
// })
// vm.$mount('#app')

三.常用Composition API

1.拉开序幕的setup

是什么?

相当于一个演员表演的舞台(station),所有的**函数,变量**都要在其体内

在这里插入图片描述

代码展示

App.vue

<template>
  <h1>一个人的信息</h1>
  <h2>姓名:{{name}}</h2>
  <h2>年龄:{{age}}</h2>
  <button @click="sayHello">说话</button>
</template>

<script>
// import { h } from '@vue/runtime-core'

export default {
  name: 'App',
  setup(){
    // 数据
    let name='张三'
    let age=18

    // 方法
    function sayHello(){
      alert(`我叫${name},我${age}岁了,你好啊!`)
    }

    // 返回一个对象(常用)
    return{
      name,
      age,
      sayHello
    }

    // 返回一个函数(渲染函数)   h函数只渲染h1--尚硅谷   不常用
    // return ()=>h('h1','尚硅谷')
  }
  
}
</script>

<style>
</style>

执行结果

在这里插入图片描述

2.ref

在这里插入图片描述

是什么?

	用来打标识,是数据变为响应式的

在这里插入图片描述

ref的基本使用

App.vue

<template>
  <h1>一个人的信息</h1>
  <!-- 这里可以写name.value,但是模板自动识别了 -->
  <h2>姓名:{{name}}</h2>
  <h2>年龄:{{age}}</h2>
  <button @click="changeInfo">修改人的信息</button>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    // 数据
    let name=ref('张三')
    let age=ref(18)

    // 方法
    function changeInfo(){
      // 因为repl上有引用对象value,所以可以用它来修改值
      name.value='李四'
      age.value=48
    }

    // 返回一个对象(常用)
    return{
      name,
      age,
      changeInfo
    }
  }
}
</script>

<style>
</style>

展示结果
在这里插入图片描述

ref处理对象类型

3 . reactive函数

在这里插入图片描述

proxy

作用:遵循响应式原理,用来响应数据
只有reactive才能把对象数据变为proxy
ref偷偷求助了reactive

在这里插入图片描述

代码展示

app.vue

<template>
  <h1>一个人的信息</h1>
  <h2>姓名:{{name}}</h2>
  <h2>年龄:{{age}}</h2>
  <h3>工作种类:{{job.type}}</h3>
  <h3>工作薪水:{{job.salary}}</h3>
  <h3>爱好:{{hobby}}</h3>
  <h3>测试的数据c:{{job.a.b.c}}</h3>
  <button @click="changeInfo">修改人的信息</button>
</template>

<script>
import { ref,reactive } from '@vue/reactivity'
export default {
  name: 'App',
  setup(){
    let name=ref('张三')
    let age=ref(18)
    let job=reactive({
      type:"前端工程师",
      salary:'30k',
      a:{
        b:{
          c:666
        }
      }
    })
    let hobby=(['抽烟','喝酒','烫头'])
    function changeInfo(){
      // ref响应的数据
      name.value='李四'
      age.value=48
      // reactive响应的数据
      job.type='UI设计师'
      job.salary='60k'
      job.a.b.c=999
      hobby[0]='学习'
    }
    return{
      name,
      job,
      age,
      hobby,
      changeInfo
    }
  }
}
</script>

<style>
</style>

结果展示

在这里插入图片描述

总结

ref:改变数据必须得通过value
reactive:是一个函数,里面必须是一个对象reactive({}),不比通过value来访问数据

4.vue3.0中得响应式原理

1.vue2得响应式

在这里插入图片描述

这样写数据不会发生变化

app.vue

<template>
  <div>
    <h1>我是Vue2写得效果</h1>
    <h2 v-show="person.name">姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2 v-show="person.sex">性别:{{person.sex}}</h2>
    <h2>爱好:{{person.hobby}}</h2>
    <button @click="addSex">添加一个sex属性</button>
    <button @click="deleteName">删除name属性</button>
    <button @click="updateHobby">修改第一个爱好的名字</button>
  </div>
</template>

<script>
  // import Vue from 'vue'
export default {
  name: 'App',
  data(){
    return{
      person:{
        name:'张三',
        sex:'男',
        age:18,
        hobby:['学习','吃饭']
      }
    }
  },
  methods:{
    addSex(){
      // // 这样写数据不会发生改变
      // console.log(this.person.sex)   //undefined
      // this.person.sex='女'
      // console.log(this.person.sex)    //女

      // 解决方案二    用$set
      this.$set(this.person,'sex','女')
      // // 解决方案一     用vue.set
      // Vue.set(this.person,'sex','女')

    },
    deleteName(){
      // // 数据不会更新
      //   console.log(this.person.name)   //张三
      //   delete this.person.name
      //   console.log(this.person.name)    //undefined

      // // 解决方案二
      // this.$delete(this.person,'name')
      // // 解决方案二
      // Vue.delete(this.person,'name','女')
    },
    updateHobby(){
      // 问题:数据不会改变
      this.person.hobby[0]='逛街' //不会更改

      // 解决方案一:
      this.$set(this.person.hobby,0,'逛街')
      // 解决方案二:
      this.person.hobby.splice(0,1,'逛街')
    }

  }
}
</script>

<style>
</style>

点击后数据不会发生改变
在这里插入图片描述

在这里插入代码片

2.vue3中得响应式

MDN文档中描述的Proxy与Reflect:

<!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>
</head>
<body>
    <script>
        let person={
            name:'张三',
            age:18
        }
        let obj={a:1,b:2}
        // 1.错误的响应式
        // Object.defineProperty('obj','c',{
        //     get(){
        //         return 3
        //     }
        // })
        // Object.defineProperty('obj','c',{
        //     get(){
        //         return 3
        //     }
        // })//会报错,因为重复定义了

        // Object与Reflect(映射)方法的区别:
        // 前者会报错,且没有返回值true/false,不能捕获错误
        // 如果想继续走,就需要try ... catch()

        // // 2.正确的响应式
        // const x1=Reflect.defineProperty('obj','c',{
        //     get(){
        //         return 3
        //     }
        // })
        // console.log(x1)//true
        // const x2=Reflect.defineProperty('obj','c',{
        //     get(){
        //         return 3
        //     }
        // })
        // console.log(x1)//false
        // if(x2){
        //     console.log('某某操作成功了!')
        // }else{
        //     console.log('某某操作失败了')
        // }

        // 3.vue的底层响应式原理
        const p=new Proxy(person,{
            // 有人读取p的某个属性时调用
            get(target,proName){
                console.log(`有人读取了p身上的${propName}属性`)
                return Reflect.get(target,propName)
            },
            // 有人修改了p的某个属性,或给p追加某个属性时调用
            set(target,propName,value){
                console.log(`有人修改了p身上的${propName}属性,我要去更新界面了`)
                Reflect.set(target,propName,value)//修改值
            },
            // 有人删除p的某个属性时调用
            deleteProperty(target,proName){
                console.log(`有人删除了p身上的${propName}属性,我要去更新界面了`)
                return Reflect.deleteProperty(target,propName)//删除值
            }
        })

    </script>
    
</body>
</html>

在这里插入图片描述

5.reactive对比ref

在这里插入图片描述

6.setup的两个注意点

笔记:

  • vue2中 props:[‘msg’,‘school’]接受的数据传到vc上去了,如果没有声明接受只能通过 a t t r s 获取,声明接受了 attrs获取 ,声明接受了 attrs获取,声明接受了attr里的数据没有。好像一个捡漏的东西
  • 插槽:父组件留坑位,子组件填坑
  • VNODE:虚拟的节点
    在这里插入图片描述
    Demo.vue
<template>
  <h1>一个人的信息</h1>
  <h2>姓名:{{person.name}}</h2>
  <h2>年龄:{{person.age}}</h2>
  <button @click="test">测试触发以下Demo组件的Hello事件</button>
</template>

<script>
import {reactive} from 'vue'
export default {
    name:'Demo',
    beforeCreate(){
        console.log('--beforeCreate--')
    },
    props:['msg','school'],// proxy:代理对象
    emits:['hello'],   //用来给app组件发射一个hello函数
    // context里面装的是{expose}
    setup(props,context){
        console.log('Context',context)
        console.log('Props:',props)
        console.log('--setup--',this)//输出结果比beforecreated早   --setup--  undefined
        // 数据
        let person=reactive({
            name:'张三',
            age:18
        })

        function test(){
            context.emit('hello',666)
        }

        // 返回一个对象(常用)
        return {
            person,
            test
        }
    }

}
</script>

<style>

</style>

app.vue

<template>
  <!-- 用来给props传数据,插槽是再里面传东西 -->
  <!-- 如果想用原生组件,后加.native....如:@click.native -->
 <Demo msg="你好啊" school="尚硅谷"></Demo>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
    setup(){
      function showHelloMsg(value){
        alert(`你好啊,你触发了hello事件,我收到的参数是${value}`)
      }
      return{
        showHelloMsg
      }
    }
}
</script>

<style>
</style>

在这里插入图片描述

7.计算属性与监视

在这里插入图片描述
app.vue

<template>
  <demo></demo>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
}
</script>

<style>
</style>

Demo.vue

<template>
  <h1>一个人的信息</h1>
  姓:<input type="text" v-model="person.firstName">
  <br>
  名:<input type="text" v-model="person.lastName">
  <br>
  全名:<input type="text" v-model="person.fullName">

</template>

<script>
import { reactive } from '@vue/reactivity'
import { computed } from '@vue/runtime-core'
export default {
    name:'Demo',
    setup(){
        let person=reactive({
            firstName:'张',
            lastName:'三'
        })
        // 计算属性-简写(没有考虑计算属性被修改的情况)
        // person.fullName=computed(()=>{
        //     return person.firstName+'-'+person.lastName
        // })


        person.fullName=computed({
            get(){
                return person.firstName+'-'+person.lastName
            },
            set(value){
                const nameArr=value.split('-')
                person.firstName=nameArr[0]
                person.lastName=nameArr[1]
            }
        })

        // 返回一个对象(常用)
        return{
            person
        }
    }


}
</script>

<style>
</style>

在这里插入图片描述
总结:
computed变为一个方法,可以写computed(()=>{})
也可以写成对象且无需返回:computed({})

8.watch属性

在这里插入图片描述
Demo.vue

<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
    <br>
    <h2>当前的信息为:{{msg}}</h2>
    <button @click="msg+='!'">修改信息</button>
    <br>
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2>薪资:{{person.job.j1.salary}}</h2>
    <button @click="person.name+='~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>


</template>

<script>
import { reactive, ref } from '@vue/reactivity'
import { watch } from '@vue/runtime-core'

export default {
    name:'Demo',
    setup(){
        let sum=ref(0)
        let msg=ref('你好啊')
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        // // 情况一:监视ref所定义的一个响应式数据
        // watch(sum,(newValue,oldValue)=>{
        //     console.log('sum变化了',newValue,oldValue)
        // },{immediate:true,deep:true})

        // 情况二:监视ref所定义的多个响应式数据
        //  watch([sum,msg],(newValue,oldValue)=>{
        //     console.log('sum或msg变化了',newValue,oldValue)
        // },{immediate:true,deep:true})

        // 情况三:监视的reactive所定义的一个响应式数据的全部属性
                // 1.注意:此处无法正确的获取oldValue
                // 2.注意:强制开启了深度监视(deep配置无效)
        watch(person,(newValue,oldValue)=>{
            console.log('person的job变化了',newValue,oldValue)
        },{deep:false})//此处的deep配置无效

        // 情况四:监视reactive所定的一个响应式数据中的某个属性
        watch(()=>person.name,(newValue,oldValue)=>{
            console.log('person的name变化了',newValue,oldValue)
        })

        // 情况五:监视reactive所定义的一个响应式数据中的某些属性
        watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
            console.log('person的name或age变化了',newValue,oldValue)
        })


        // 特殊情况
        watch(()=>person.job,(newValue,oldValue)=>{
            console.log('person的job变化了',newValue,oldValue)
        },{deep:true})//此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效

        return {
            sum,
            msg,
            person
        }
    }
}
</script>

<style>
</style>

app.vue

<template>
  <demo></demo>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.newValue变成一个数组,不再仅仅是一个数
2.reactive里面的对象,自动有深度监视功能。watch不用开启深度deep监视
3.当ref({})里面是个对象时,会走reactive(内部会生成一个proxy代理对象)路线,且必须通过.value来取值

watch时value的值

Demo.vue

<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
    <br>
    <h2>当前的信息为:{{msg}}</h2>
    <button @click="msg+='!'">修改信息</button>
    <br>
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2>薪资:{{person.job.j1.salary}}</h2>
    <button @click="person.name+='~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>


</template>

<script>
import { reactive, ref } from '@vue/reactivity'
import { watch } from '@vue/runtime-core'

export default {
    name:'Demo',
    setup(){
        let sum=ref(0)
        let msg=ref('你好啊')
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        console.log(person)

		//不要用.value监视一个具体的值 如0,会报错
		//也不要监视一个具体的值
        watch(sum,(newValue,oldValue)=>{
            console.log('sum的值变化了',newValue,oldValue)
        })

        // 问题访问不到,因为ref走的是reactive的路线需要开起深度监视
        // 解决方案一:  通过访问.value
        watch(person.value,(newValue,oldValue)=>{
            console.log('person的值变化了',newValue,oldValue)
        })
        
        // 方案二:开启deep
        watch(person,(newValue,oldValue)=>{
            console.log('person的值变化了',newValue,oldValue)
        },{deep:true})

        return {
            sum,
            msg,
            person
        }
    }
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.当sum=ref(0),不能用watch(sum.value)的.value来访问,因为是具体的值
2.proxy相当于地址,地址不变引用不变

watchEffec函数

在这里插入图片描述
Demo.vue

<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
    <br>
    <h2>当前的信息为:{{msg}}</h2>
    <button @click="msg+='!'">修改信息</button>
    <br>
    <h2>姓名:{{person.name}}</h2>
    <h2>年龄:{{person.age}}</h2>
    <h2>薪资:{{person.job.j1.salary}}</h2>
    <button @click="person.name+='~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>


</template>

<script>
import { reactive, ref } from '@vue/reactivity'
import { watch, watchEffect } from '@vue/runtime-core'

export default {
    name:'Demo',
    setup(){
        let sum=ref(0)
        let msg=ref('你好啊')
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        watchEffect(()=>{
            const x1=sum.value
            const x2=person.job.j1.salary
            console.log('watchEffect所指定的回调执行了')
        })

        return {
            sum,
            msg,
            person
        }
    }
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.watchEffect不说它监视谁
2.computed函数初始化时执行一次,依赖的数据发生变化时执行一次
3.watchEffect有点像,谁用了,监视谁
4.watchEffect注重过程,computed注重值

9.Vue3生命周期

生命周期钩子两种写法:

  • 配置项式:与setup平级
  • 组合式API式:写在setup里面
    在这里插入图片描述
    Demo.vue
<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
</template>

<script>
import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated } from '@vue/runtime-core'
import { ref } from 'vue'


export default {
    name:'Demo',
    setup(){
        console.log('----setup---')
        let sum=ref(0)
        onBeforeMount(()=>{
            console.log('---onBeforeMount---')
        })
        onMounted(()=>{
            console.log('---onMounted---')
        })
        onBeforeUpdate(()=>{
            console.log('---onBeforeUpdate---')
        })
        onUpdated(()=>{
            console.log('---onUpdated---')
        })
        onBeforeUnmount(()=>{
            console.log('---onBeforeUnmount---')
        })
        onUnmounted(()=>{
            console.log('---onUnmounted---')
        })

        return{
            sum
        }

    }, 
    
    // 2.通过配置项形式使用生命周期钩子
    beforeCreate(){
        console.log('---beforeCreate---')
    }, 
    created(){
        console.log('---created---')
    },
    beforeMount(){
        console.log('---beforeMount---')
    },
    mounted(){
        console.log('---mounted---')
    },
    beforeUpdate(){
        console.log('---beforeUpdate---')
    },
    updated(){
        console.log('---updated---')
    },
    beforeUnmount(){
        console.log('---beforeUpdate---')
    },
    unmounted(){
        console.log('---updated---')
    },


}
</script>

<style>
</style>

app.vue

<template>
  <button @click="isShowDemo=!isShowDemo">切换隐藏/显示</button>
  <demo v-if="isShowDemo"></demo>
</template>

<script>
import { ref } from '@vue/reactivity'
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
    setup(){
      let isShowDemo=ref(true)
      return{
        isShowDemo
      }
    }
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.vue3可以继续使用vue2的生命周期钩子但有两个改名

  • beforeDestroy---->beforeUnmount
  • destroyed----> unmounted
    2.setup执行在beforeCreate之前
    3.setup与beforeCreate是平级的关系,可以写在同一个层级
    4.vue2在挂载之前可以执行beforeCreate(),created().但vue3必须先挂载,再执行
    5.折叠#region-----#endregion
    6.钩子对应关系vue2vue3
    beforeCreate
    =>setup()
    created
    =====>setup()
    beforeMount()=>onBeforeMount
    mounted
    =====>onMounted
    beforeUpdate====>onBeforeUpdate
    update=========>onUpdated
    beforeUnmounted====>onBeforeUnmount
    unmounted=======>onUnmounted

9.自定义hook函数

在这里插入图片描述
app.vue

<template>
  <button @click="isShowDemo=!isShowDemo">切换隐藏/显示</button>
  <demo v-if="isShowDemo"></demo>
  <hr>
  <test></test>
</template>

<script>
import { ref } from '@vue/reactivity'
import Demo from './components/Demo.vue'
import Test from './components/test.vue'
export default {
    name: "App",
    components:{Demo, Test},
    setup(){
      let isShowDemo=ref(true)
      return{
        isShowDemo
      }
    }
}
</script>

<style>
</style>

Demo.vue

<template>
    <h2>当前求和为:{{sum}}</h2>
    <button @click="sum++">点我+1</button>
    <br>
    <h2>当前点击鼠标的坐标为:x:{{point.x}},y:{{point.y}}</h2>
</template>

<script>
import { ref } from '@vue/reactivity'
import usePoint from '../hooks/usePoint'

export default {
    name:'Demo',
    setup(){
        let sum=ref(0)
        let point=usePoint()

        return{
            sum,
            point
        }
    }
 
}
</script>

<style>
</style>

test.vue

<template>
  <h2>我是Test组件</h2>
  <h2>当前点击鼠标的坐标为:{{point.x}},y:{{point.y}}</h2>

</template>

<script>
    import usePoint from '../hooks/usePoint';
    export default {
        name:'Test',
        setup(){
            const point = usePoint()
            return{
                point
            }
        }

    }
</script>

<style>

</style>

hooks / usePoint.js

<template>
  <h2>我是Test组件</h2>
  <h2>当前点击鼠标的坐标为:{{point.x}},y:{{point.y}}</h2>

</template>

<script>
    import usePoint from '../hooks/usePoint';
    export default {
        name:'Test',
        setup(){
            const point = usePoint()
            return{
                point
            }
        }

    }
</script>

<style>

</style>

在这里插入图片描述
总结:

  • 1.hook只是一个普普通通的js,可以提高功能的复用
  • 2.组件和hook功能都一样

10.toRef(把什么变成ref)

在这里插入图片描述
问题:复制的数据非响应式

<!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>
</head>
<body>
    <script>
        let person={
            name:'张三',
            age:18
        }
        let p=new Proxy(person,{
            set(target,propName,value){
                console.log(`${propName}被修改了,我要去更新页面`)
                // target[propName]=value
                Reflect.set(target,propName,value)
            }
        })
        // 问题:
        // 这里是数据而非响应式
        let name=p.name
        
    </script>
</body>
</html>

在这里插入图片描述


Demo.vue

<template>
    <h4>{{person}}</h4>
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>薪资:{{job.j1.salary}}</h2>
    <button @click="name+='~'">修改姓名</button>
    <button @click="age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>


</template>

<script>
import { reactive, toRef,toRefs } from '@vue/reactivity'

export default {
    name:'Demo',
    setup(){
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        // // 1.toref()处理响应式引用关系
        // const name1=person.name
        // console.log('%%%',name1)

        // const name2=toRef(person,'name')
        // console.log('####',name2)
        
        // 2.toRefs()处理多个数据
        const x=toRefs(person)
        console.log('******',x)


        return{
            person,
            // 解决方案一:ref
            // name:toRef(person,'name'),
            // age:toRef(person,'age'),
            // salary:toRef(person.job.j1,'salary'),

            // 解决方案二:toRefs()处理多个数据
            ...toRefs(person)
        }
    }
 
}
</script>

<style>
</style>

app.vue

<template>
  <demo></demo>
  <hr>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
    setup(){

      return{
        
      }
    }
}
</script>

<style>
</style>

执行结果
在这里插入图片描述

总结:
1.ref是复制的数据,原数据不变,toRef是引用关系(通过getter,setter指向)
2.toRefs()只能处理第一层,不能深层次响应

三.其他Composition API

1.shallowReactive与shallowRef

在这里插入图片描述
Demo.vue

<template>
    <h4>当前的x值是:{{x}}</h4>
    <button @click="x={y:888}">点我x+1</button>
    <button @click="x.y++">点我x.y++</button>
    <br>
    <h4>{{person}}</h4>
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>薪资:{{job.j1.salary}}</h2>
    <button @click="name+='~'">修改姓名</button>
    <button @click="age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>


</template>

<script>
import { reactive,toRefs,shallowRef} from '@vue/reactivity'

export default {
    name:'Demo',
    setup(){
        //1.shallowReactive:只处理第一层数据的响应式
        // let person.shallowReactive({
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        let x=shallowRef({
            y:0
        })
        console.log('*****',x)
        
        return{
            x,
            person,
            ...toRefs(person)
        }
    }
 
}
</script>

<style>
</style>

app.vue

<template>
  <demo></demo>
  <hr>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
    setup(){

      return{
        
      }
    }
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.reactive会把对象里所有的东西变为响应式
2.ref的value:proxy, shallowRed的value:Object,拿来就用

2.readonly与shallowReadonly

页面不变得两种情况:

  • 1.页面不是响应式得
  • 2.页面不让改
    在这里插入图片描述

总结:
起到保护作用,不许修改

3.toRaw与markRaw

在这里插入图片描述
demo.vue

<template>
    <h4>当前求和为:{{sum}}</h4>
    <button @click="sum++">点我++</button>
    <br>
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <h2>薪资:{{job.j1.salary}}</h2>
    <h3 v-show="person.car">座驾信息:{{person.car}}</h3>
    <button @click="name+='~'">修改姓名</button>
    <button @click="age++">增长年龄</button>
    <button @click="job.j1.salary++">涨薪</button>
    <button @click="showRawPerson">输出最原始得person</button>
    <button @click="addCar">给人添加一台车</button>
    <button @click="person.car.name+='!'">换车名</button>
    <button @click="person.car.price++">换价格</button>
    <button @click="changePrice">换价格</button>
</template>

<script>
import { reactive,toRefs,ref, toRaw, markRaw} from '@vue/reactivity'

export default {
    name:'Demo',
    setup(){
        let sum=ref(0)
        let person=reactive({
            name:'张三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        }) 
        function showRawPerson(){
            const p=toRaw(person)
            p.age++
            console.log(p)
        }

        function addCar(){
            let car={name:'奔驰',price:40}
            person.car=markRaw(car)
        }

        function changePrice(){
            person.car.price++
            console.log(person.car.price)
        }
        
        return{
            sum,
            person,
            ...toRefs(person),
            showRawPerson,
            addCar,
            changePrice
        }
    }
 
}
</script>

<style>
</style>

app.vue

<template>
  <demo></demo>
  <hr>
</template>

<script>
import Demo from './components/Demo.vue'
export default {
    name: "App",
    components:{Demo},
    setup(){

      return{
        
      }
    }
}
</script>

<style>
</style>

执行结果
在这里插入图片描述

总结:
1.toRaw()只能处理reactive
2.setup只会调用一次,
3.值是undefined,不展示

4.customRef

custom:自定义

  • 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制
    trigger():让vue重新去读取模板
    track():追踪数据。有追踪,get才会重新解析

实现防抖效果:
app.vue

<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>

</template>

<script>
import { trigger } from '@vue/reactivity'
import { customRef } from 'vue'

export default {
    name: "App",
    components:{},
    setup(){
      // 自定义一个ref----名为:myRef
      function myRef(value,delay){
        let timer
        return customRef((track,trigger)=>{
          return{
            get(){
              console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`)
              track()//通知vue追踪value的变化(提前和get商量一下,让它认为这个value是有用的)
              return value
            },
            set(newValue){
              console.log(`有人把myRef这个容器中数据改了:${newValue}`)
              clearTimeout(timer)
              timer=setTimeout(()=>{
                value=newValue
                trigger()//通知vue去重新解析模板
              },delay)
            }
          }
        })
      }

      // let keyWord=ref('hello')  //使用vue提供的ref
      let keyWord=myRef('hello',500)//使用程序自定义的ref

      return{
        keyWord
      }
    }
}
</script>

<style>
</style>

执行结果
在这里插入图片描述
总结:
1.customRef()是一个自定义的ref函数
2.有人读,运行get()。有人改,使用set()
3.cls—快速打出console

5.provide与inject

在这里插入图片描述
app.vue

<template>
  <div class="app">
    <h3>我是App组件(组),{{name}}----{{price}}</h3>
    <Child></Child>
  </div>
</template>

<script>
import { reactive, toRefs } from '@vue/reactivity';
import Child from './components/Child.vue';
import { provide } from '@vue/runtime-core';
export default {
    components: { Child },
    setup(){
      let car=reactive({name:'奔驰',price:'40w'})
      provide('car',car)//给自己的后代组件传递数据
      return{
        ...toRefs(car)
      }
    }
}
</script>

<style>
.app{
    background-color: gray;
    padding: 10px;
}
</style>

Child.vue

<template>
    <div class="child">
      <h3>我是Child组件(子)</h3>
        <Son></Son>
    </div>
  </template>
  
  <script>
import { inject } from '@vue/runtime-core';
import Son from './Son.vue';
  export default {
    components: { Son },
    setup(){
        let x=inject('car')
        console.log(x,'Chold-----')
    }
}
  </script>
  
  <style>
  .child{
      background-color: skyblue;
      padding: 10px;
  }
  </style>

Son.vue

<template>
    <div class="son">
      <h3>我是SOn组件(孙)----{{car.name}}---{{car.price}}</h3>
    </div>
  </template>
  
  <script>
import { inject } from '@vue/runtime-core'
  export default {
    setup(){
        let car=inject('car')
        return{
            car
        }
    }
  
  }
  </script>
  
  <style>
  .son{
      background-color: orange;
      padding: 10px;
  }
  </style>

在这里插入图片描述

总结:
1.只要app.vue 通过provided一下,他的任意子组件都可以用,哪怕是跨级
2.inject:注入
3.用于组件间通信

6.响应式数据的判断

在这里插入图片描述
app.vue

<template>
  <h3>我是App组件(祖)</h3>
</template>

<script>
import { isProxy, isReactive, isReadonly, isRef, reactive, readonly, toRefs ,ref} from '@vue/reactivity'

export default {
    components: {},
    setup(){
      let car=reactive({name:'奔驰',price:'40w'})
      let sum=ref(0)
      let car2=readonly(car)

      console.log(isRef(sum))
      console.log(isReactive(car))
      console.log(isReadonly(car2))
      console.log(isProxy(car))
      console.log(isProxy(sum))   //false
      return{
        ...toRefs(car)
      }
    }
}
</script>

<style>
</style>

在这里插入图片描述

总结:
1.ref底层用的是底层Object.defined
2.readonly处理了响应式数据,但返回的还是proxy,而不是Object

四.Composition API的优势

在这里插入图片描述

在这里插入图片描述

五.新组件

1.Fragment

在这里插入图片描述

2.Teleport

在这里插入图片描述
app.vue

<template>
  <div class="app">
    <h3>我是App组件</h3>
    <Child></Child>
  </div>
</template>

<script>
import Child from "./components/Child.vue";

export default {
    components: { Child },
    setup(){

    }
}
</script>

<style>
  .app{
    background-color: gray;
    padding: 10px;
  }
</style>

Child.vue

<template>
  <div class="child">
    <h3>我是Child组件</h3>
    <Son></Son>
  </div>
</template>

<script>
import Son from "./Son.vue";
export default {
    components: { Son }
}
</script>

<style>
    .child{
        background-color: skyblue;
        padding: 10px;
    }
</style>

Son.vue

<template>
  <div class="son">
    <h3>我是Son组件</h3>
    <Dialong></Dialong>
  </div>
</template>

<script>
import Dialong from './Dialong.vue';
export default {
    components: { Dialong }
}
</script>

<style>
.son{
    background-color: orange;
    padding: 10px;
}
</style>

Dialong.vue

<template>
  <div>
    <button @click="isShow=true">点我弹个窗</button>
    <teleport to="body">
        <div class="mask"  v-if="isShow">
            <div class="dialog">
                <h3>我是一个弹窗</h3>
                <h4>一些内容</h4>
                <h4>一些内容</h4>
                <h4>一些内容</h4>
                <button @click="isShow=false">关闭弹窗</button>
            </div>
        </div>
    </teleport>
  </div>
</template>

<script>
import {ref} from 'vue'
export default {
    setup(){
        let isShow=ref(false)


        return {
            isShow
        }
    }

}
</script>

<style>
    .mask{
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.5);

    }
.dialog{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-50%);
    text-align: center;
    width: 300px;
    height: 300px;
    background-color: green;
}
</style>

执行结果
在这里插入图片描述

3.Suspense–异步

在这里插入图片描述
app.vue

<template>
  <div class="app">
    <h3>我是App组件</h3>
    <Suspense>
      <template v-slot:default>
        <Child></Child>
      </template>
      <template v-slot:fallback>
        <h3>稍等,加载中...</h3>
      </template>
    </Suspense>
  </div>
</template>

<script>
// import Child from "./components/Child.vue";//静态引入
import { defineAsyncComponent } from "vue";
const Child=defineAsyncComponent(()=>import('./components/Child'))//异步引入
export default {
    components: { Child },
    setup(){

    }
}
</script>

<style>
  .app{
    background-color: gray;
    padding: 10px;
  }
</style>

Child.vue

<template>
  <div class="child">
    <h3>我是Child组件</h3>
    {{sum}}
  </div>
</template>

<script>
    import { ref } from 'vue'
export default {
    components: {},
    async setup(){
        let sum=ref(0)
        let p=new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve({sum})
            },3000)
        })
        return await p
    }
}
</script>

<style>
    .child{
        background-color: skyblue;
        padding: 10px;
    }
</style>

执行结果
在这里插入图片描述

总结:
1.Suspense里面有两个插槽,第一个:要放置加载慢的插槽。第二个:应急插槽-先加载快的
2.子组件的setup不返回数,主页面就不加载更新

六.其他

1.全局API的转移

在这里插入图片描述

在这里插入图片描述

2.其他改变

在这里插入图片描述
在这里插入图片描述

张天禹 Vue3+TypesScript 2020年9月18日,Vue.js发布版3.0One Piece(n4800+次提交40+个RFC600+次PR300+贡献者3.3.4setup是Vue3中一个新的配置项,值是一个函数,它是“表演的舞台,组件中所用到的:数据、方法、计算属性、监视…等等,均配置在setup中。setup函数返回的对象中的内容,可直接在模板中使用。setup中访问this是undefined。setup函数会在之前调用,它是“领先”所有钩子执行的。姓名:{{name}} 阅读详情

相关推荐

Vue3笔记 尚硅谷张天禹

Vue3笔记尚硅谷张天禹 markdown格式

(尚硅谷张天禹-升级版)Vue2+Vue3超全三万六千字笔记

点击事件

S903784597的博客 5395

普冉PY32F002B ADC内部参考电压VREFINT的误差补偿与低功耗优化实践

本文详细介绍了普冉PY32F002B单片机在锂电池供电场景下ADC内部参考电压VREFINT的误差补偿与低功耗优化实践。通过分析GPIO配置、分压电阻匹配、采样时间设置等硬件设计要点,结合实时测量VREFINT电压值和软件补偿算法,有效提升了ADC测量精度至5mV以内,并实现了分压电路功耗控制与采样频率优化,为低成本消费电子项目提供了完整的解决方案。

846

[暂不持续更新] Vue2+Vue3 框架学习笔记(尚硅谷张天禹版)

* 本笔记是跟随B站张天禹讲师的[尚硅谷Vue2.0 + Vue3.0全套教程丨vuejs从入门到精通](https://www.bilibili.com/video/BV1Zy4y1K7SH/?spm_id_from=333.337.search-card.all.click&vd_source=475d52c1c9e04f0181802504eb57ae7a),附上直达车。 * 本笔记更多为笔者个人使用,笔者的要求是达到**能用的水平**就可以,所以专业前端的同学而慎重考虑选择该笔记。很多原理性的东西笔

wjw89的博客 1336

ArcGIS属性表汉字转拼音

接着我安装了一个编辑器“PyCharm Community Edition 2019.3.3\bin\pycharm64.exe”,在里面添加“pypinyin”包,然后将其设置为arcgis的编辑器和调试程序,还是失败;我在10.6的机器上折腾了上面几步,直到两周后脚本突然运行成功,我也不确定是哪一步导致pypinyin包配置成功,因此将心得体会写出来,如果过一段时间,打开10.2的机器运行脚本成功了,再写后续.......,按照“配置方法1:”进行尝试,显示配置失败。

2301_77413856的博客 1295

Oracle21C Windows安装全攻略:从下载到配置环境变量,避开ORA-12514的坑

本文详细介绍了Oracle21C在Windows系统上的安装全流程,包括环境准备、安装包验证、分步安装指南、数据库实例创建与配置、环境变量精准配置等关键步骤,特别针对常见的ORA-12514错误提供了解决方案,帮助用户顺利完成安装并避免常见问题。

ooo22的博客 415

尚硅谷Vue2-3(张天禹老师) 学习笔记

......

w小浩的博客 4957

Qt OpenGL 3D 点云数据显示

在Qt中使用OpenGL显示3D点云数据是一个常见的需求,特别是在计算机视觉、机器人学和三维重建等领域。下面我将介绍一个基本的实现方案。

深之JohnChen的专栏 1238

Vue3.0尚硅谷(讲师:张天禹)视频学习笔记

尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通之Vue3.0

qq_48105178的博客 4598

基于 国产USRP B210 的通信+侦测+干扰三合一实验平台,解锁无线攻防全场景!

在当代复杂电磁环境与多样化通信需求并存的背景下,软件定义无线电(SDR)技术正展现出前所未有的系统灵活性与功能可重构性。由两台USRP-LW B210软件无线电设备模拟无线链路通信过程,能够模拟多种无线通信信号传输及图像传输场景,适用于通信协议验证、抗干扰测试及教学实验。,支持"通信-侦测-干扰-优化"的闭环实验流程,为无线通信领域的教学科研与工程应用提供了一套经济高效、功能完备的解决方案。系统可对通信链路信号进行快速、自动化侦测、识别、告警,并支持多种干扰信号生成、模式切换及效果评估功能。

luowave2012的博客 832

Burp Suite手工验证CORS漏洞的四步闭环法

CORS(跨域资源共享)是Web应用实现跨域通信的基础机制,其安全本质在于服务端对Origin头的校验逻辑与响应头组合的语义一致性。当服务端错误地返回Access-Control-Allow-Origin: *并配合Access-Control-Allow-Credentials: true,或采用弱校验(如字符串包含匹配)时,将导致敏感数据泄露与凭据劫持风险。该漏洞难以被自动化扫描器发现,因其依赖请求上下文、认证状态及动态策略判断。Burp Suite作为核心工具,需通过构造跨域请求、捕获预检响应、交叉验

weixin_30596343的博客 512

前端篇vue:视频+笔记

Vue2笔记——(尚硅谷张天禹Vue笔记)_尚硅谷vue2笔记 张天禹-优快云博客尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通_哔哩哔哩_bilibili

qadnkz的专栏 235

基于STM32开发板的USB MIDI键盘实现

在本文中,我们介绍了如何使用STM32开发板和相应的软件工具来实现USB MIDI键盘。通过配置STM32CubeMX和编写相应的源代码,我们能够将STM32开发板转换为一个功能齐全的USB MIDI设备。我们将使用STM32开发板和相应的软件工具来实现这一功能,并提供相应的源代码供参考。此时,您应该可以使用STM32开发板作为USB MIDI键盘,并在按键按下时听到相应的音符。在STM32CubeMX中,选择适当的STM32型号,并启动一个新的项目。然后,将生成的可执行文件烧录到STM32开发板中。

2301_79326616的博客 1588

B站尚硅谷张天禹老师课程配套笔记下载

我整理了张天禹老师Vue2(53,000+字)和Vue3(12,000+字)的系统学习笔记,包含数百张课程截图和深入讲解,适合各阶段学习者。笔记可下载,还可免费获取内部培训资料。

LIANGJIANGLI的专栏 536

PX4从放弃到精通(二十二):日志

文章目录前言一、下载日志二、ulog转CSV三、利用flightplot软件分析PX4的ulog日志1 windos安装2 ubuntu18.04安装四、使用PlotJuggler分析PX4日志五、设置日志记录条件六、添加自定义日志消息 前言 PX4 1.10以上固件 QGC 一、下载日志 将飞控链接地面站,在下图页面点击“刷新”,即可看到保存的日志(前提是要有TF卡) 选择需要下载的日志,点击右侧的“下载”,然后选择目录即可进行下载,如果想擦除所有的日志,可以点击右侧的“擦除全部” 二、ulog转CS

超维空间科技的博客 6793

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Vue3+ts(day03:ref和reactive)

Vue3+ts中的ref和reactive)

weixin_51591826的博客 1822

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Vue3笔记——(尚硅谷张天禹Vue笔记)

vue3笔记

csdnidofkdy2138的博客 4590

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Vue3尚硅谷张天禹笔记

修改名字

青山猿的博客 2569

尚硅谷Vue3(天禹老师主讲)的笔记

这是尚硅谷Vue3(天禹老师主讲)的笔记,放在这里只是为了方便自己查看 文章目录Vue3快速上手1.Vue3简介2.Vue3带来了什么1.性能的提升2.源码的升级3.拥抱TypeScript4.新的特性一、创建Vue3.0工程1.使用 vue-cli 创建2.使用 vite 创建二、常用 Composition API1.拉开序幕的setup2.ref函数3.reactive函数4.Vue3.0中的响应式原理vue2.x的响应式Vue3.0的响应式5.reactive对比ref6.setup的两个注意点.

fengxiandada的博客 6226

Vue3+ts(day01:Vue3简介、初始化Vue3工程)

Vue3简介、初始化Vue3工程

weixin_51591826的博客 1249

Vue2+Vue3笔记(尚硅谷张天禹老师)day01

Vue2+Vue3笔记(尚硅谷张天禹老师)

qq_45418837的博客 1064

Vue2+Vue3笔记(尚硅谷张天禹老师)day03

Vue2+Vue3笔记 尚硅谷张天禹

qq_45418837的博客 595

Vue2+Vue3笔记(尚硅谷张天禹老师)day02

Vue2+Vue3笔记(尚硅谷张天禹老师)

qq_45418837的博客 719

尚硅谷天禹老师主讲-Vue3-06-路由

优点:URL更加美观,不带有#,更接近传统网站URL;缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。缺点:URL带有#不太美观,且在SEO优化方面性能较差。如何使得上述新闻的小li里面不是固定的,可以循环得到,News.vue。如果想要点击"首页"、“新闻”,切换路由页面,样式也跟着变化。如果想要点击"首页",自动引入路由,不需要手动改变,,只要点击"关于",就会重新挂载,点击其他,就会卸载。通过点击导航,视觉上“消失”了的路由组件,默认是被。展示区必须:,不然无法看到页面。

qq_51148337的博客 608

计算机书籍&视频推荐

.......后续再补充。

Ana的blog 443

尚硅谷 张天禹老师vue2笔记(方便自己查阅)

视频链接: https://www.bilibili.com/video/BV1Zy4y1K7SH?p=2&spm_id_from=pageDriver 尚硅谷 张天禹老师vue2笔记 脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存

Maynor的博客 5358
上一篇: Node.js的Buffer(缓存区)
下一篇: JSON笔记
ACBYCL
博客等级 码龄5年 8粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值