Vue3总结。。。

vue3


模板语法


1、动态参数

<!-- 动态参数 -->

<!-- 如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href -->

<a:[a.href]="a.url">百度一下</a>

<!-- 自定义绑定事件名 -->

<a@[eventName]="doSomething">{{ count }}点击加1</a>

data () {

return {

rawHtml: '<spanstyle="color: red">This should be red.</span>',

href: 'href',

a: {

href: 'href',

url: 'http://www.baidu.com'

},

eventName: 'click'

};

},

methods: {

doSomething() {

console.log(1)

}

}

响应式基础


1、reactive()

<template>

<div>

<div>{{ state.count }}</div>

<button@click="addCount">点击count累加</button>

</div>

</template>

<scriptsetup>

import { reactive } from'vue';

exportdefault {

setup() {

// 利用reactive设置响应式数据

conststate=reactive({ count: 0 })

// 使count++的函数

functionaddCount() {

state.count++

}

// 暴露state,addCount

return {

state,

addCount

}

}

}

</script>

2、<script setup>

  • 在 setup() 函数中手动暴露大量的状态和方法非常繁琐。幸运的是,我们可以通过使用构建工具来简化该操作。当使用单文件组件(SFC)时,我们可以使用 <script setup> 来大幅度地简化代码。

  • 备注:什么是单文件组件

  • 在 Vue 应用中,提供了 .vue 为后缀的文件,我们将这类的文件,称之为“单文件组件”,也就是说,每一个文件,都是一个单独的组件。(其实我们平时每个.vue文件都是单文件组件)

  • 单文件组件写法

  • <template>
    <div>
    <div>{{ state.count }}</div>
    <button@click="addCount">点击count累加</button>
    </div>
    </template>

    <scriptsetup>
    import { reactive } from'vue';
    // 利用reactive设置响应式数据
    conststate=reactive({ count: 0 })

    // 使count++的函数
    functionaddCount() {
    state.count++
    }

    </script>

    <stylescopedlang='less'>

    </style>

3、reactive()的局限性

  • 仅对对象类型有效(对象、数组和 Map、Set这样的集合类型),而对 string、number 和 boolean 这样的 原始类型无效。

  • 因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失:

  • <template>
    <div>
    <div>{{ state.count }}</div>
    <button@click="countValue(count)">点击触发函数</button>
    </div>
    </template>

    <scriptsetup>
    import { reactive } from"vue";

    /**
    * 因为 Vue 的响应式系统是通过属性访问进行追踪的,
    * 因此我们必须始终保持对该响应式对象的相同引用。
    * 这意味着我们不可以随意地“替换”一个响应式对象,
    * 因为这将导致对初始引用的响应性连接丢失:
    */
    // let state = reactive({ count: 0 })
    // state = reactive({ count: 1 })

    letstate=reactive({ count: 0 })
    // 此处的n不是响应式的
    letn=state.count
    n++
    // count也不是响应式的
    let { count } =state
    count++

    functioncountValue(count) {
    consta=state.count++
    console.log('解构后的count,失去了响应式', count)
    console.log('响应式count', a)
    }


    </script>

4、ref()

  • 允许创建可以使用任何值类型的响应式 ref

  • <template>
    <div>
    <!-- 模板中使用不需要加value -->
    <div>ref定义响应式(简单): {{ count }}</div>
    <div>ref定义响应式(复杂):{{ countObj }}</div>
    <button@click="addCount">+1</button>
    </div>
    </template>

    <scriptsetup>
    import { ref } from"vue";
    // 简单数据类型设置响应式
    letcount=ref(100)
    letcountObj=ref({ count: 1 })
    letobj= {
    foo: ref(1)
    }

    // foo是解构出来的,但也是响应式的
    const { foo } =obj

    functionaddCount() {

    count.value++
    countObj.value.count++
    obj.foo.value++
    console.log(countObj.value, foo.value)
    }
    </script>

    <stylescopedlang='less'>

    </style>

5、响应性语法糖(待总结)

计算属性


  • computed()`方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过 publishedBooksMessage.value访问计算结果。

  • 计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value

  • <template>
    <div>
    <p>Has published books:</p>
    <!-- 不使用计算属性时 -->
    <div>{{ author.books.length > 0 ? 'Yes' : 'No' }}</div>
    <!-- 使用计算属性时 -->
    <div>{{ publishedBooksMessage }}</div>
    <button@click="changeComputed">尝试修改计算属性</button>
    <!-- 可修改的计算属性 -->
    <div>你的名字是: {{ fullName }}</div>
    </div>
    </template>

    <scriptsetup>
    import { computed, reactive, ref } from'vue'
    constauthor=reactive({
    name: 'John Doe',
    books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
    ]
    })
    // 计算属性
    letpublishedBooksMessage=computed(() => {
    returnauthor.books.length>0?'Yes' : 'No'
    })


    constfirstName=ref('John')
    constlastName=ref('Doe')

    constfullName=computed({
    // getter
    get() {
    returnfirstName.value+' '+lastName.value
    },
    // setter
    set(newValue) {
    // 注意:我们这里使用的是解构赋值语法
    [firstName.value, lastName.value] =newValue.split(' ')
    }
    })

    constchangeComputed= () => {
    fullName.value='Xiao Fu'
    }
    </script>

    <stylescopedlang='less'>
    </style>

1、计算属性和方法的区别

  • 不考虑其他东西,两者可实现相同的效果,都可以去依赖其他项去计算

  • 区别在于计算属性值会基于其响应式依赖被缓存,计算属性仅会在其响应式依赖更新时才会重新计算,依赖项不变,计算属性也不会发生变化,不会去重复执行getter函数

  • 而方法总是会在重新渲染时再次执行函数,不管依赖项有没有发生改变

  • 函数形式的计算属性是只读的,当你尝试修改一个计算属性时,你会收到一个运行时警告(官网解释,但自己试了一下没有警告,但模板渲染的值没有进行更新)

  • 计算属性设置为对象形式时,会有get和set方法,set方法可以对计算属性进行修改,对象形式的计算属性是可读可写的,修改之后如果模板用到这个计算属性时,也会发生相应的更新

2、总结

  • 官方建议计算属性是基于原有数据的一个派生,依赖于其他值进行变化,其他值发生变化计算属性才会跟着变化,计算属性应该是只读的,不要去直接更改它,更建议通过依赖项的改变去触发它的重新计算。

类与样式绑定


  • <template>
    <div>
    <!-- 字面量方式绑定 -->
    <div:class="{ active: isActive }">
    1111
    </div>
    <!-- 对象方式绑定 -->
    <div:class="classObject">222</div>

    <!-- 数组形式绑定 -->
    <div:class="[activeClass, errorClass]">333</div>
    </div>

    </template>

    <scriptsetup>
    import { reactive, ref } from'vue'

    constisActive=ref(true)
    // 对象方式直接绑定
    constclassObject=reactive({
    active: true,
    'text-danger': true
    })

    constactiveClass=ref('active')
    consterrorClass=ref('text-danger')
    </script>

    <stylescoped>
    .active {
    margin: 10px;
    width: 100px;
    height: 100px;
    background-color: orange;
    }

    .text-danger {
    font-size: 30px;
    }
    </style>

条件渲染


v-if和v-show

  • 和vue2一致

  • 两者都能控制dom元素的显隐,区别在于

  • v-if实现元素显隐的原理是DOM的创建销毁,会经历组件的创建和销毁

  • v-show实现元素显隐的原理是进行样式的控制,通过操控display: none / block进行控制,无论元素是否显示,它都会进行渲染,在显隐切换的过程中不会经历组件的创建和销毁

  • 因此来说,v-if有更高的切换开销,v-show有更高的渲染开销,当频繁进行切换时,v-show相对较好,当绑定条件很少改变时,v-if相对更加合适

  • 和vue2的区别

  • v-if和v-for同时使用时,v-if的优先级更高

  • 也就意味着v-if的条件无法访问到v-for作用域内定义的变量别名

  • 不建议两个出现在一起,造成性能的浪费

列表渲染


v-for

  • 和vue2基本一致

  • 小妙招

  • 假设有一个数组,数组每一项是数组,如果想要遍历小数组的每一项该怎么弄

  • 可以先遍历大数组,v-for的item就是每一个小数组,再遍历item,item的每一项就是小数组的每一项

  • <ulv-for="numbers in sets">
    <liv-for="n in even(numbers)">{{ n }}</li>
    </ul>

    <script>
    constsets=ref([
    [1, 2, 3, 4, 5],
    [6, 7, 8, 9, 10]
    ])

    functioneven(numbers) {
    returnnumbers.filter((number) =>number%2===0)
    }
    </script>

事件处理


  • v-on:事件类型 / @事件类型进行触发事件执行相应的方法逻辑

  • 可以跟一个方法,也可以编写内联JavaScript代码

  • 方法没有参数时可以只写方法名,当有参数时可以(参数)进行传参处理

  • 需要访问原生dom事件时,可以传入一个特殊的$event, 或者使用内联箭头函数

  • <template>
    <div>
    <!-- 使用特殊的 $event 变量 -->
    <button@click="warn('Form cannot be submitted yet.', $event)">
    Submit
    </button>

    <!-- 使用内联箭头函数 -->
    <button@click="(event) => warn('Form cannot be submitted yet.', event)">
    Submit
    </button>
    </div>
    </template>

    <scriptsetup>
    functionwarn(a, e) {
    console.log(a, e);
    }
    </script>

暂时未写功能描述

  • 事件修饰符

  • .stop

  • .prevent

  • .self

  • .capture

  • .once

  • .passive

  • 按键修饰符

  • .enter

  • .tab

  • .delete (捕获“Delete”和“Backspace”两个按键)

  • .esc

  • .space

  • .up

  • .down

  • .left

  • .right

  • 系统按键修饰符

  • .ctrl

  • .alt

  • .shift

  • .meta

  • 当出现链式使用时,例如@keyup.ctrl.alt,它会再ctrl + alt 键弹起时触发

  • .exact:使用系统按键修饰符不跟.exact时,指定按键触发时同时按下别的键也会触发,但加上.exact后就不会触发,有且只能指定按键触发,多一个都不行

  • 鼠标按键修饰符

  • .left

  • .right

  • .middle

生命周期钩子(待定)


watch侦听器


  • 侦听存在的数据,当数据发生变化时,可以执行一些逻辑代码

  • watch(侦听数据, () => { 逻辑代码编写处 })
    // 侦听数据可以是单个响应式数据,也可以是getter函数或者是多个数据组成的数组
    // 单个 ref
    watch(x, (newX) => {
    console.log(`x is ${newX}`)
    })

    // getter 函数
    watch(
    () =>x.value+y.value,
    (sum) => {
    console.log(`sum of x + y is: ${sum}`)
    }
    )

    // 多个来源组成的数组
    watch([x, () =>y.value], ([newX, newY]) => {
    console.log(`x is ${newX}and y is ${newY}`)
    })

  • 不能直接侦听响应式对象的属性,需要通过getter的方式侦听

  • <template>
    <div>
    <div>商品的数量是:{{ goods.num }}</div>
    <button@click="changeNum">点击增加商品数量</button>
    </div>
    </template>

    <scriptsetup>
    import { reactive, watch } from"vue";

    letgoods=reactive({
    name: '饼干',
    num: 5,
    children: {
    name: '旺旺',
    num: 10
    }
    })

    constchangeNum= () => {
    goods.num++
    }

    // 直接侦听响应式对象,会隐式地创建一个深层侦听器,不管多深层次,一个值改变了都会触发
    // watch(goods, ({ children : { num } }) => {
    // console.log(num)
    // })

    // 直接侦听响应式对象的某个属性,会警告并且侦听器不执行
    // watch(goods.num, (obj) => {
    // console.log(obj)
    // })

    // 要侦听单个属性时,可以用getter函数的形式
    watch(
    () =>goods.num, (num) => {
    console.log(num)
    },
    )

    </script>

  • 直接侦听响应式对象的属性时控制台的警告

  • 侦听器watch有第三个参数,可开启立即执行以及深层侦听,对象的方式设置

  • watch(
    () =>state.someObject,
    (newValue, oldValue) => {
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
    },
    { deep: true }
    )

watchEffect()

  • // 不需要专门侦听todoId,watchEffect会立即执行,并且也会依赖于侦听值,再本例子中当todoId发生改变时,就会触发函数进行执行
    watchEffect(async () => {
    constresponse=awaitfetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
    )
    data.value=awaitresponse.json()
    })

watch和watchEffect的区别

  • watch 只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。

  • watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。

  • // 沿用上述例子
    // watch写法
    watch(() =>goods.num, () => {
    console.log(num)
    }, { immediate: true })

    // watchEffect写法
    // 相较而言更加简洁
    // 当goods的num发生改变时就会触发回调中的逻辑,并且他是立即执行的,刚加载未做出改变时会立即执行一次
    watchEffect(() => {
    console.log(goods.num)
    })

侦听器回调触发的时机

  • 当我们更改了响应式状态,它可能会同时触发Vue组件更新和侦听器回调

  • 默认情况下,用户创建的侦听器回调,都会在Vue组件更新之前被调用,这意味着我们在侦听器回调中访问的DOM将是被Vue更新之前的状态

  • 想要在侦听器回调访问被Vue更新之后的DOM,需要指明flush: 'post'选项

  • watch(source, callback, {
    flush: 'post'
    })

    watchEffect(callback, {
    flush: 'post'
    })

    // 也有一个专门的东西
    watchPostEffect(() => {
    /* 在 Vue 更新后执行 */
    })

停止侦听器

  • 一般而言只要我们在setup()或者<script setup>中以同步的方式编写侦听器,会自动绑定到宿主组件实例,并且会在宿主组件卸载时自动停止。因此,在大多数情况下,你无需关心怎么停止一个侦听器。

  • 但如果时异步创建的侦听器的话,他不会绑定到当前组件上,必须手动停止它,防止内存泄漏

  • constunwatch=watchEffect(() => {})

    // ...当该侦听器不再需要时
    unwatch()

模板引用


  • ref,在vue2中可以获取到dom元素,vue3中同样如此,但写法又有所不同

  • 组合式api中获取模板应用,需要声明一个同名的ref

  • <scriptsetup>
    import { ref, onMounted } from'vue'

    // 声明一个 ref 来存放该元素的引用
    // 必须和模板里的 ref 同名
    constinput=ref(null)

    onMounted(() => {
    input.value.focus()
    })
    </script>

    <template>
    <inputref="input"/>
    </template>

  • 我们只可以在组件挂载后才能访问模板引用。如果我们想在模板中的表达式上访问 input,在初次渲染时会是 null。这是因为在初次渲染前这个元素还不存在。

如果你需要侦听一个模板引用 ref 的变化,确保考虑到其值为 null 的情况:

  • watchEffect(() => {
    if (input.value) {
    input.value.focus()
    } else {
    // 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)
    }
    })

v-for中也可以使用模板引用

  • <scriptsetup>
    import { ref, onMounted } from'vue'

    constlist=ref([1, 2, 3])

    constitemRefs=ref([])

    onMounted(() => {
    alert(itemRefs.value.map(i=>i.textContent))
    })
    </script>

    <template>
    <ul>
    <liv-for="item in list"ref="itemRefs">
    {{ item }}
    </li>
    </ul>
    </template>

  • ref 数组并不保证与源数组相同的顺序。

组件上的 ref

  • 和vue2类似,ref绑定到子组件上时,可以获取到子组件实例,可以获取到子组件的属性以及方法

  • <scriptsetup>
    import { ref, onMounted } from'vue'
    importChildfrom'./Child.vue'
    // 2、同名声明
    constchild=ref(null)

    onMounted(() => {
    // 3、child.value 是 <Child /> 组件的实例
    })
    </script>

    <template>
    <!--1、子组件绑定ref-->
    <Childref="child"/>
    </template>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Vue 3中的Vue Router API发生了一些变化。在Vue 2中,我们可以通过this.$route和this.$router来控制路由。而在Vue 3中,我们需要使用新的API来实现相同的功能。 引用[1]中提到,现在我们可以使用useRoute来获取当前路由信息,相当于Vue 2中的this.$route。而useRouter相当于Vue 2中的this.$router。 在代码中,我们需要引入useRouter和useRoute这两个函数,可以通过以下方式进行引入: ```javascript import { useRouter, useRoute } from "vue-router"; ``` 在setup函数中,我们可以使用useRouter来获取路由实例,使用useRoute来获取当前路由信息。例如: ```javascript setup() { let router = useRouter(); let route = useRoute(); console.log("接收到的参数", route.query); return { router }; } ``` 在Vue 3中,我们可以使用router.push来进行页面跳转,类似于Vue 2中的this.$router.push。例如: ```javascript router.push('/suscomp'); router.push({ path: '/suscomp', query: { a: 1, b: 2 } }); ``` 另外,在Vue 3中,我们可以在全局中使用$router、$route、<router-view/>和<router-link/>这些API。在main.js中,我们需要将router实例通过app.use()方法进行挂载。例如: ```javascript import { createApp } from 'vue'; import App from './App.vue'; import router from "@/router"; const app = createApp(App); app.mount('#app'); app.use(router); ``` 总结来说,Vue 3中的Vue Router API发生了一些变化,我们需要使用useRoute和useRouter来获取路由信息和路由实例,使用router.push来进行页面跳转,并在main.js中将router实例挂载到app上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不断蜕变灬青春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值