• vue3与vue2的不同内容


    目录

    一、main.js入口文件的不同

    二、组件中的模板结构允许没有跟标签

    三、setup(这个非常重要)

     四、ref函数

    五、reactive函数

    六、彻底摆脱.value

    七、父传子props接收 ,props没有$attrs接收

    八、setup执行时机在beforeCreate之前执行一次,里面打印this是undefined

    九、setup函数有两个参数

    十、computed计算属性

    十一、watch监视

    十二、watchEffect函数

     十三、生命周期

     十四、自定义hook函数

    十五、toRef、toRefs函数

    十六、customRef

    十七、provide与inject

    十八、响应式数据的判断(返回的都是布尔值)

    十九、Teleport(传送门)

    二十、路由

     二十一、vue3+使用icon图标问题(重要是个大坑)

    完结啦  有些没写的可以去官方文档看看


    一、main.js入口文件的不同

    1. // 引入的不再是构造函数,引入了一个名为creacteApp的工厂函数
    2. import { createApp } from 'vue'
    3. import './style.css'
    4. import App from './App.vue'
    5. // 创建应用示例对象--->app
    6. const app = createApp(App)
    7. //把组件APP挂载到#app节点上
    8. app.mount('#app')

    二、组件中的模板结构允许没有跟标签

    三、setup(这个非常重要)

    组件中用到的:数据、方法等等,均要配置配置在setup中

    setup中的变量不用this.变量获取了  因为本身就在同一个方法中(同一个作用域)

    setup返回一个对象,则对象中的属性、方法,在模板中均可以直接使用(重点)

    1. <script>
    2. export default {
    3. name: 'App',
    4. // 此时只是测试一下setup, 暂时不考虑响应式的问题。
    5. setup() {
    6. // 数据
    7. let name = '张三'
    8. let age = 18
    9. // 方法
    10. function sayHello() {
    11. alert(`我叫${name}. 我${age}岁了, 你好呀`)
    12. }
    13. //返回一个对象(常用) 对象里的属性可以直接在模板中使用
    14. return {
    15. name: name,
    16. age: age,
    17. sayHello,
    18. }
    19. }
    20. }
    21. script>

     效果:

     四、ref函数

    作用: 定义一个响应式的数据

    语法: const xxx = ref(initValue)

          创建一个包含响应式数据的引用对象(reference对象,简称ref对象)

          操作数据: xxx.value

          模板中读取数据不需要.value, 例如;

    {{xxx}}

    1. <script>
    2. import {ref} from 'vue'
    3. export default {
    4. name: 'App',
    5. setup() {
    6. // 数据
    7. let name = ref('张三')
    8. let age = ref(18)
    9. let obj = ref({ // 这里对象用的是ref
    10. type: '前端工程师',
    11. salery: '30k',
    12. })
    13. // 方法
    14. function changeInfo() {
    15. name.value = "李四",
    16. age.value = 48,
    17. obj.value.type = 'UI设计师', // 由于用的是ref 所以修改值才用obj.value.type
    18. obj.value.salary = '60k', // 由于用的是ref 所以修改值才用obj.value.salary
    19. }
    20. //返回一个对象(常用) 对象里的属性可以直接在模板中使用
    21. return {
    22. name: name,
    23. age: age,
    24. obj,
    25. changeInfo,
    26. }
    27. }
    28. }
    29. script>

    效果:

    五、reactive函数

    题外话:对象解构会失去响应式   大聪明们

    作用: 定义一个对象类型的响应式数据(基本类型不要用它, 要用ref函数)

    语法: const 代理对象 = reactive(源对象) 用来接收一个数组或对象,返回一个代理对象(proxy的实例对象)

    reactive定义的响应式数据是“深层次的”

    内部是基于ES6的proxy实现的,通过代理对象操作源对象内部数据进行操作

    1. // 大家有没有发现  上面用ref函数处理对象的时候如果对象多层嵌套呢
    2. // 例如:
    3. let obj = ref( { obj: {obj: '旧值'} } )
    4. // 修改值的时候
    5. obj.value.obj.value.obj = '修改的新值' 
    6. // 上面是不是很麻烦
    7. // 用reactive函数就省略了上面的.value 
    8. // 例如:
    9. let obj1 = reactive( { obj: {obj: '旧值'} } )
    10. // 修改值的时候
    11. obj1.obj.obj = '修改的新值' 
    12. // 修改数组:
    13. let hobby = reactive( ['抽烟', '喝酒', '烫头'] )
    14. // 修改值的时候
    15. hobby[0] = '学习'    ==>    结果为: ['学习', '喝酒', '烫头']

    六、彻底摆脱.value

    1. <script>
    2. import {ref, reactive} from 'vue'
    3. export default {
    4. name: 'App',
    5. setup() {
    6. // 把所有的数据都定义在一个类里面 然后用reactive进行改造响应式数据
    7. let person = reactive({
    8. name: '张三',
    9. age: 18,
    10. obj: {
    11. type: '前端工程师',
    12. salery: '30k',
    13. a: {
    14. b: {
    15. c: 666
    16. }
    17. }
    18. },
    19. hobby: ['抽烟', '喝酒', '烫头']
    20. })
    21. // 方法
    22. function changeInfo() {
    23. person.name = "李四",
    24. person.age = 48,
    25. person.obj.type = 'UI设计师',
    26. person.obj.salery = '60k',
    27. person.obj.a.b.c = '999',
    28. person.hobby[0] = '学习'
    29. }
    30. //返回一个对象(常用) 对象里的属性可以直接在模板中使用
    31. return {
    32. person,
    33. changeInfo,
    34. }
    35. }
    36. }
    37. script>

    效果:

    七、父传子props接收 ,props没有$attrs接收

    父传子props接收 ,props没有接收$attrs就接收,$attrs是一个对象,在模板用的时候通过$.attrs.属性名获取父组件传过来的值    props接收的  可以直接在模板上写属性名

    但是我们不建议这样用   最好都要用props接收   因为能控制接收的类型

    八、setup执行时机在beforeCreate之前执行一次,里面打印this是undefined

    九、setup函数有两个参数

    1.参数一:是props,props要定义props接收父传过来的属性,然后props再作为setup参数一,

    这是为什么这么做呢: 我猜是这样的 因为setup执行时机在beforeCreate之前执行一次,this是undefined,所以无法通过this获取值只能通过传入props, 不然setup内部获取不了外面传进来的值

    在setup内部打印出来的数据类型是一个Proxy对象  也就是一个响应式数据

    2.参数二:参数二是一个普普通通的参数,里面有

    1)、$attrs(就是捡漏props没写的属性就写在这里)

    2)、emit(触发自定义事件):

            用法:参数二.emit('方法名', 传出去的数据) ==> 例如: 参数二.emit('hello', 666)

            上面写法如果有警告的话在setup外面写一个emits: ['hello']就好了

    3)、slots插槽  

    注意: vue3中已经废弃slot="aaa"

            改用v-slot:aaa

    十、computed计算属性

    在vue3中也可以像vue2那种套路写计算属性,但是我不推荐使用,你想想都他么学vue3了,还使用旧的干嘛,别人新的东西有新的好,不然别人弄新的干嘛  所以这里用vue3的的computed

    1. <script>
    2. import {reactive, computed} from 'vue'
    3. export default {
    4. name: 'Demo',
    5. setup() {
    6. let person = reactive({
    7. firstName: '张',
    8. lastName: '三',
    9. })
    10. // 计算属性 -- 简写 (没有考虑计算属性被修改)
    11. //persom.fullName = computed(() => {
    12. //return person.firstName + '-' + person.lastName
    13. //})
    14. // 计算属性 -- 完整写法(考虑读写)
    15. persom.fullName = computed({
    16. get() {
    17. return person.firstName + '-' + person.lastName
    18. },
    19. set(value) {
    20. const nameArr = value.split('-')
    21. person.firstName = nameArr[0]
    22. person.lastName = nameArr[1]
    23. }
    24. })
    25. return {
    26. person
    27. }
    28. }
    29. }
    30. script>

    十一、watch监视

    watch的三个参数: 参数一: 监视谁    参数二: 监视的回调     参数三: 监视的配置

    1)、watch监视ref定义的数据

    1. <script>
    2. import {ref, watch} from 'vue'
    3. export default {
    4. name: 'Demo',
    5. setup() {
    6. // 数据
    7. let sum = ref(0)
    8. let msg = ref('你好啊')
    9. // 情况一:监视ref所定义的一个响应式数据
    10. // watch(sum, (newValue, oldValue) => {
    11. // console.log('sum变了', newValue, oldValue); // sum变了 1 0
    12. //}, {immediate: true, deep: true})
    13. // 情况二:监视ref所定义的多个响应式数据
    14. watch([sum, msg], (newValue, oldValue) => {
    15. console.log('sum或msg变了', newValue, oldValue);
    16. // 1.点击加1按钮 sum或msg变 [1, '你好啊'] [0, '你好啊']
    17. // 2.点击修改信息按钮 sum或msg变 [1, '你好啊!'] [0, '你好啊']
    18. }, {immediate: true})
    19. // 返回对象
    20. return {
    21. sum,
    22. msg
    23. }
    24. }
    25. }
    26. script>

    2)、watch监视reactive定义的数据(对象监听默认开启深度监听)

    注意: 只要reactive直接改造过的对象 :

                    (1) deep默认是true  并且是无法设置的 

                    (2)无法正确的获取oldValue的值

    1. <script>
    2. import {ref, reactive, watch} from 'vue'
    3. export default {
    4. name: 'Demo',
    5. setup() {
    6. let person = reactive({
    7. name: '张三',
    8. age: 18,
    9. job: {
    10. j1: {
    11. salary: 20
    12. }
    13. }
    14. })
    15. /*
    16. 情况三:监视reactive所定义的一个响应式数据的全部数据
    17. 1.注意:此处无法正确获取odlValue(odlValue每次获取都是最新的数据)
    18. 2.注意: 强制开启了深度监视(deep配置无效)
    19. */
    20. watch(person, (newValue, oldValue) => {
    21. console.log('person变了', newValue, oldValue);
    22. }, {immediate: true}) // 此处deep无效
    23. // 情况四:监视reactive所定义的一个响应式数据中的某个属性(这个能用)
    24. watch(() => person.name, (newValue, oldValue) => {
    25. console.log('person的name变了', newValue, oldValue); // 张三~ 张三
    26. },)
    27. // 情况五: 监视reactive所定义的一个响应式数据中的某写属性(这个能用)
    28. watch([() => person.name, () => person.age], (newValue, oldValue) => {
    29. console.log(newValue, oldValue); // ['张三~', 18] ['张三', 18]
    30. },)
    31. //特殊情况 能监听 要开启深度监听
    32. watch(() => person.job, (newValue, oldValue) => {
    33. console.log(newValue, oldValue);
    34. }, {deep: true}) // 这里监听的是通过reactive改造过的一个对象里面的一个属性并且属性的值是一个对像 可以开启深度监听 但是也是拿不到正确是oldValue的值
    35. // 返回对象
    36. return {
    37. person
    38. }
    39. }
    40. }
    41. script>

    3)、watch时value的问题

    1. <script>
    2. import {ref, reactive, watch} from 'vue'
    3. export default {
    4. name: 'Demo',
    5. setup() {
    6. let sum = ref(0)
    7. let msg = ref('你好吗')
    8. let person = reactive({
    9. name: '张三',
    10. age: 18,
    11. job: {
    12. j1: {
    13. salary: 20
    14. }
    15. }
    16. })
    17. // 基本类型
    18. // 注意为什么监听的不是sum.value呢 因为sum.value是一个值 值为0 你监视个0干嘛
    19. // 要监听sum sum是一个ref加工过的 是一个对像
    20. watch(sum, (newValue, oldValue) => {
    21. console.log('值变化了', newValue, oldValue)
    22. })
    23. // 复杂类型
    24. // 用ref改造的对象 有两种监听方法
    25. // 方法一:用.value
    26. watch(person.value, (newValue, oldValue) => {
    27. console.log('值变化了', newValue, oldValue)
    28. })
    29. // 方法二: 不用.value 用deep
    30. watch(person, (newValue, oldValue) => {
    31. console.log('值变化了', newValue, oldValue)
    32. }, {deep: true})
    33. // 返回对象
    34. return {
    35. sum,
    36. msg,
    37. person
    38. }
    39. }
    40. }
    41. script>

    十二、watchEffect函数

    1)、watch的套路是:既要指明监视的属性,也要指明监视的回调。

    2)、watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,就监视哪个属性。

    3)、watchEffect有点像computet:

            ①但computed注重的计算出来的值(回调的返回值),所以必须写返回值。

            ②而watchEffect更注重的是过程(回调的函数体),所以不用写返回值。

    1. <script>
    2. import {ref, reactive, watchEffect} from 'vue'
    3. export default {
    4. name: 'Demo',
    5. setup() {
    6. let sum = ref(0)
    7. let msg = ref('你好吗')
    8. let person = reactive({
    9. name: '张三',
    10. age: 18,
    11. job: {
    12. j1: {
    13. salary: 20
    14. }
    15. }
    16. })
    17. watchEffect(() => {
    18. const x1 = sum.value
    19. const x2 = person.job.j1.salary
    20. console.log('z只要sum.value和person.job.j1.salary的值发生变化就执行watchEffect')
    21. })
    22. // 返回对象
    23. return {
    24. sum,
    25. msg,
    26. person
    27. }
    28. }
    29. }
    30. script>

     十三、生命周期

    vue3.0提供了Composition API形式的生命周期钩子

    vue2  ==>vue3的生命周期对应

    beforeCreate ==> setup() : data 和 methods 中的 数据都还没有初始化

    created ==> setup():data 和 methods 都已经被初始化好了

    beforeCreate不能写在setup内  因为setup相当于beforeCreate和created生命周期  但是这两个可以写在setup外面

    beforeMount ==> onBeforeMount:尚未把模板渲染到 页面中

    mounted  ==>  onMounted:模板渲染到 页面中了

    beforeUpdate ==> onBeforeUpdate:data中数据是最新的  页面中显示的数据还是旧的 

    updated ==> onUpdated:页面中显示的数据和data里面的数据都是最新的 

    beforeUnmount ==> onBeforeUnmount:页面销毁前

    unmounted ==> onUnmounted: 页面销毁后

     

     十四、自定义hook函数

    什么是hook:本质是一个函数,把setup函数中使用的Composition API进行了封装

    自定义hook的优势: 复用代码,让setup中的逻辑更清楚易懂

    1.拿到复用的代码

     2.在src下创建一个hook文件    再创建一个js文件   把复用的代码方法到一个方法里

     3.使用

    十五、toRef、toRefs函数

    1.

    ref和toRef都可以用于创建一个响应式数据,那他们之间有什么区别呢?
    利用ref将对象中的属性变成响应式数据,修改响应式数据是不会影响到原始数据。

    1. import {ref} from 'vue';
    2. export default {
    3. name:'App'
    4. setup(){
    5. let obj = {name : 'alice', age : 12};
    6. let newObj= ref(obj.name); // 这里相当于 newObj= ref('alice') 它与obj没有一毛钱关系
    7. function change(){
    8. newObj.value = 'Tom';
    9. console.log(obj,newObj)
    10. // obj = {name : 'alice', age : 12}
    11. // newObj = 'Tom'
    12. }
    13. return {newObj,change}
    14. }
    15. }

    上述代码,当change执行的时候,响应式数据发生改变,而原始数据obj并不会改变。
    原因在于,ref的本质是拷贝,与原始数据没有引用关系

    2.

    toRef将对象中的属性变成响应式数据,修改响应式数据是会影响到原始数据的。

    修改通过toRef创建的响应式数据,会触发UI界面的更新。所以,toRef的本质是引用,与原始数据有关联

    1. import {toRef} from 'vue';
    2. export default {
    3. name:'App'
    4. setup(){
    5. let obj = {name: 'alice', age: 12};
    6. let newObj= toRef(obj, 'name'); // toRef的本质时让obj.name的引用指向了变量newObj
    7. function change(){
    8. newObj.value = 'Tom'; // 由于obj.name的引用地址也指向了newObj所以修改newObj也会修改obj.name的值
    9. console.log(obj, newObj)
    10. // obj = {name: 'Tom', age: 12}
    11. // newObj 等于 'Tom'
    12. }
    13. return {newObj,change}
    14. }
    15. }

    change执行的时候,响应式数据发生改变,原始数据obj里面的属性改变,UI界面会更新

    3.使用toRefs(可以批量创建多个ref对象)

     总结:

    作用: 创建一个ref对象,其value值指向另一个对象中的某个属性

    语法: const name = toRef(person, 'name')

    应用: 要将响应式对象中的某个属性单独供应给外部使用时

    扩展: toRefs与toRef功能一致,但可以批量创建多个ref对象,

    语法:toRefs(person) 

    十六、customRef