vue3 - 基础知识讲解(模板语法等)

128 阅读8分钟

今天想看看最新的 vue3 现在是怎么样的,照着教程一步步做

一 安装 create-vue

执行

npm init vue@latest
npm run dev // 开始报错

如果你的 node 还是老版本,那会和我一样遇到这个报错 报错内容

failed to load config from /Users/wxl/Documents/practice/vue/vue3/vue1013/vite.config.js
error when starting dev server:
Error: Cannot find module 'node:url'

查了下,这是因为 vue@latest 这个包依赖的node版本比较高导致的 我本地的node版本是14.16,node官方推荐版本是16.x,最新版本是18.x,我先升级下本地版本 ok,安装成功了.

这个包安装成功后会询问你关于要创建的项目的配置, 因为是学习阶段,所以我都用的默认选择的 No。 都安装好了之后,本地开启 5173 端口,自动运行了一个 vue3 的项目

截屏2022-10-13 上午9.08.53.png

二 API风格

vue 的 组件有两种书写风格:选项式 API组合式 API 选项式 API 就是 vue2 的写法,这两种写法主要区别在于 script 里的代码。 选项式 API 里, script主要内容就是一个对象,data,methods,mounted 等 是它的方法。

而组合式 API 里的 script 写法,比较类似传统的函数式编程

两种 API 风格的优缺点

  • 选项式 API 更易上手,对初学者更好
  • 组合式 API 更自由灵活

官方的说法是。

  • 当不需要构建工具,或者是地复杂场景,推荐使用选项式 API
  • 当应用比较复杂,适合用组合式 API+单文件组件

三 模板语法

指令

v-html

在网站上动态渲染任何 html 是非常危险的,容易造成 XSS 漏洞,仅在内容安全可信时再使用 v-html,并且永远不要使用用户提供的 HTML 内容

动态绑定多个值

v-bind可以动态绑定多个值

let xObject = {age:3,name:'xiaolan'}
<div v-bind='xObject'></div>

Vue 中所有数据绑定中都支持完整的 js 表达式 比如

{{message.split('').reverse().join('')}}

全局对象

没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window 上的属性。然而,你也可以自行在 app.config.globalProperties 上显式地添加它们,供所有的 Vue 表达式使用。

这种 vue 里的全局对象其实最好少定义,如果确实遇到场景了就 定义在main.js里.

let app = createApp(App);
app.config.globalProperties.userName = "晓兰";

app.mount("#app");

动态参数值

// 动态参数
<a v-bind:[attributeName]="url"></a>
// 简写
<a :[attributeName]="url></a>

动态函数

<a @[eventName]="doSomething">

动态参数的限制 动态参数表达式因为某些字符的缘故有一些语法限制,比如空格和引号,在 html 里是不合法的,比如

<a :['foo' + bar]="value"></a>

所以如果要传入复杂的动态参数,推荐使用计算属性 动态属性名不能包含大写字母,因为浏览器会强行把他转化成小写

修饰符

修饰符以.开头比如.prevent 完整的指令语法

image.png

四 响应式基础

虽然属性也可以不在 data 上定义,直接向组件实例添加新属性,但这个属性将无法触及响应式更新

Vue 自动为 methods 种的方法绑定一了永远指向组件实例的 this.你不应该在定义 methods 时使用箭头函数,因为箭头函数没有自己的 this 上下文

nextTick

这个方法的应用场景是:vue 有一个 nextTick模块,如果你更新一个属性的状态多次,他是不会实时更新真实 dom 的,而是更新虚拟 dom.

vue 把缓存他们直到更新周期的"下个时机",以确保无论你进行了多少次状态更改,每个组件走只需要更新一次.

如果要等待一个状态改变后的 DOM 更新完成,可以使用 nextTick 这个全局 api

应用场景

比如页面有个播放器,然后你手动更改了播放器的 src 地址. 然后你要让播放器开始播放,就要调用它的 play 方法

// template
<audio ref="audio" :src="url"></audio>

// script
this.url = 'x';
this.$refs.audio.play(); // 会报错,因为这个时候真实 dom播放器的 url 属性其实还没有更新

我引用网上一段别人遇到的场景代码来说明吧

把代码改成这样就可以了

 x.url = 'x';
 this.$nextTick((function() {
      this.$refs.audio.play();
 });

nextTick 在 vue2.5 改过版.源码地址在这 nextTick

深层响应式

比如 data的 return 里的代码是

data(){ 
    return {
        obj: {
            nested: {count:0},
            arr:['foo']
    }
}

methods里的代码是

// 以下都会按照期望工作
this.obj.nested.count++
this.obj.arr.push('baz')

响应式代理 vs 原始对象

如果是组合式 api 的话记得把想要深层响应的属性是 new reactive 出来的.否则这种深层响应是没用的.

推荐做法是只有对象,数组类才申明响应式代理. 其他的比如字符串和数字,申明原始对象即可.

let userList = reactive(["晓兰", "小凤"]);

你也可以直接创建一个浅层响应式对象.一般仅在某些特殊场景中需要.

响应式变量

用 ref 来定义响应式变量

import {ref} from 'vue' //注意vue是小写 字母开头而不是大写
let count = ref(1)
count.value +=1 // 注意是调用 count.value 而不是 count

有状态方法

export default {
    methods: {
        click:debounce(function () {
        
        },500)
    }
}

这种函数是有问题的,它在运行时维护者一个内部状态.如果多个组件实例都共享这一个函数,那么他们之间会互相影响

要保持每个组件实例的防抖函数都彼此独立,我们可以改为在 created 生命周期钩子中创建这个预置防抖的函数.

五 计算属性

推荐使用计算属性来描述依赖响应式的复杂逻辑.

计算属性和函数的不同 ,计算属性值会基于其响应式依赖被缓存.一个计算属性仅会在其响应式依赖更新时才会重新计算.

比如下面的计算属性永远不会跟新,因为Date.now()并不是一个响应式依赖

computed: {
    now() {
        return Date.now()
    }
 }

计算属性默认是可读的,只有在某些时候你才能用到 getter 和 setter 来创建

computed: {
    fullName: {
        get () {
            return ''
            }
        set (newValue) {
            // 这里用的是解构赋值写法
            [this.firstName, this.lastName ] = newValue.split(' ')
        }
    }
}

这样当你再运行 this.fullName = 'a b'时,setter 会被调用,this.firstName 和 this.lastName 会被更新

最佳实践

避免直接修改计算属性值 计算属性的返回值应该被视为可读的,并且永远不应该被更改--应该更新它所依赖的源状态以触发新的计算

六 类与样式

clss 可以直接绑定一个 class 对象,比如

 data () {
     return {
         classObject: {
             active: true,
             'text-danger':false
         }
     }
 }

template 代码

<div :class="classObject"></div>

:style属性值采用驼峰命名

<div :style="{'font-size': fontSize+'px'}"></>

直接绑定一个样式对象会更简洁点

七 条件渲染

template 组件就可以直接用 v-if,这样最后的渲染结果 可以并不会包含这个 template

<template v-if="ok">
    <h1>我是标题</h1>
</template>

v-show 不支持在 template 元素伤是用,也不能和 v-ese 搭配

v-if和 v-show

v-if 是"真实的"按条件渲染,因为他确保了在切换的时候条件区块内的事件监听器和子组件都会被销毁与重建.

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事.条件区块只有当条件首次为 true 时才会被渲染.

相比之下,v-show 简单的多,元素不管初始条件如何,始终都会被渲染,只有 css display 属性会被切换

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销. 因此,如果需要频繁切换,就用 v-show 就好,如果在运行时绑定条件很少改变,则 v-if 更适合.

v-if 和 v-for

同时使用 v-if 和 v-for 是不推荐的,因为这样二者的优先级不明显.

当 v-if 和 v-for 同时存在于一个元素上的时候,v-if 会被首先执行.

八 列表渲染

可以在定义 v-for 的变量别名时使用结构,和结构函数参数类似.比如

<li v-for="({message},index) in items">

</li>

也可以使用 of 来作为分隔符来替代 in,这更接近 js 的迭代器语法

<div v-for="item of items"></div>

v-for与对象

可以使用 v-for 来遍历一个对象的所有属性.遍历的顺序会基于该对象调用 object.keys()的返回值来决定.

<li v-for="value in myObject">{{value}}
</li>

也可以提供第二个参数表示属性名(例如 key)

<li v-for="(value,key) in myObject">
{{key}} : {{value}}
</li>

第三个参数表示位置索引

<li v-for="(value,key, index) in myObject">
{{index}}. {{key}} : {{value}}
</li>

template上的 v-for

<template v-for="item in items">
xxx
</template>

同时使用 v-for 和 v-if 是不推荐的,可以在外新包装一层 template.

<template v-ofr="todo intodos">
    <li v-if="!todo.isComplete"></li>
</template>

通过 key 管理状态

推荐在任何可行的时候为 v-for 提供一个 key 的 attribute,除非所迭代的 dom 内容非常简单(例如:不包含组件或有状态的 dom 元素)

key 绑定的默认是一个基础类型的值,例如字符串或 number 类型.不要用对象作为 v-for 的 key.

事件处理

我们能通过event.target.tagName获取到被绑定的dom 元素

修饰符

使用修饰符时要注意顺序,因为相关代码是以相关顺序生成的.

.passive.会让滚动事件的调用立刻发生而不是等到 onScroll 调用完成. 可以使用.passive来干山移动端的滚屏性能

事件修饰符

表单输入绑定

select

如果 v-model 表达式的初始值不匹配任何一个选择项,<select> 元素会渲染成一个“未选择”的状态。在 iOS 上,这将导致用户无法选择第一项,因为 iOS 在这种情况下不会触发一个 change 事件。因此,我们建议提供一个空值的禁用选项

<select v-model="selected">
                    <option disabled value="">Please select one</option>   
        <option>A</option>
        <option>B</option>
        <option>C</option> 
</select>