主页

vue3.x 和 vue2.x 版本对比

vue2.x 中绝大多数的 API 与特性,在 vue3.x 中同样支持。同时,vue3.x 中还新增了 3.x 所特有的功能、并废弃了某些 2.x 中的旧功能:
新增的功能有组合式API、多根节点组件、更好的 TypeScript 支持等
废弃的旧功能有过滤器、不再支持 $on、$off、$once 实例方法等

过滤器兼容性

过滤器仅在 vue2.x 和 1.x 中受支持,再 vue3.x 的版本中剔除了过滤器相关的功能
可以使用计算属性或方法代替被剔除的过滤器功能

单页面应用程序 SPA(Single Page Application)

优点

1. 良好的交互体验

  • 单页应用的内容改变不需要重新加载整个页面
  • 获取数据也是通过 Ajax 异步获取
  • 没有页面之间的跳转,不会出现“白屏现象”

2. 良好的前后端工作分离模式

  • 后端专注于提供 API 接口,更易实现 API 接口的复用
  • 前端专注于页面的渲染,更利于前端工程化的发展

3. 减轻服务器的压力

  • 服务器只提供数据,不负责页面的合成逻辑的处理,吞吐能力提高几倍

缺点

任何一种技术都有自己的局限性

1. 首屏加载慢

  • 路由懒加载
  • 代码压缩
  • CDN 加速
  • 网络传输压缩

2. 不利于 SEO

  • SSR 服务器端渲染

快速创建 vue 的 SPA 项目

  1. 基于 vite 创建 SPA 项目
  2. 基于 vue-cli 创建 SPA 项目

vite 的基本使用

创建 vite 项目

按照顺序执行以下命令,即可基于 vite 创建 vue3.x 的工程化项目:

npm init vite-app 项目名称

cd 项目名称
npm install
npm run dev

梳理项目的结构

  • node_modules 目录用来存放第三方依赖包
  • public 是公共的静态资源目录
  • src 是项目的源代码目录(写的所有代码都要放在此目录下)
  • .gitignore 是 Git 的忽略文件
  • index.html 是 SPA 单页面应用程序中唯一的 HTML 页面
  • package.json 是项目的包管理配置文件

在 src 这个项目源代码目录下

  • assets 目录用来存放项目中所有的静态资源文件(css、fonts等)
  • components 目录用来存放项目中所有的自定义组件
  • App.vue 是项目的根组件
  • index.css 是项目的全局样式表文件
  • main.js 是整个项目的打包入口文件

vite 项目的运行流程

在工程化的项目中,vue 要做的事情很单纯:通过 main.js App.vue 渲染到 index.html 的指定区域中

  1. App.vue 用来编写待渲染的模板结构
  2. index.html 中需要预留一个 el 区域
  3. main.js 把 App.vue 渲染到了 index.html 所预留的区域中

在 App.vue 中编写模板结构

清空 App.vue 的默认内容,并书写以下的模板结构:

<temptale>
    <h1>这是 App 根组件</h1>
</template>

在 index.html 中预留 el 区域

打开 index.html 页面,确认预留了 el 区域:

<body>
    <!-- id 为 app 的 div 元素,就是将来 vue 要控制的区域 -->
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
</body>

在 main.js 中进行渲染

按照 vue3.x 的标准用法,把 App.vue 中模板内容渲染到 index.html 页面的 el 区域中:

// 1. 从 vue 中按需导入 createApp 函数,
//    createApp 函数的作用:创建vue 的 “单页面应用程序实例”
import { creeateApp } from 'vue'
// 2. 导入待渲染的 App 组件
import App from './App.vue'

// 3. 调用 createApp() 函数,返回的是 “单页面应用程序的实例”,用常量 spa_app 进行接收
//    同时把 App 组件作为参数传给 createApp 函数,表示要把 App 渲染到 index.html 页面上
const spa_app = createApp(App)
// 4. 调用 spa_app 实例的 mount 方法,用来指定 vue 实际要控制的区域
spa_app.mount('#app')

在 template 中定义根节点

在 vue2.x 的版本中,<template> 节点内的 DOM 结构仅支持单个根节点
但是,在 vue3.x 的版本中,<template> 中支持定义多个根节点

组件的注册

vue 中注册组件的方式分为 “全局注册” 和 “局部注册” 两种,其中:

  • 被全局注册的组件,可以再全局任何一个组件内使用

// 在 main.js 中全局注册组件
import { createApp } from 'vue'
import App from './App.vue'
// 1. 导入 Swiper 和 Test 两个组件
import Swiper from './components/MySwiper.vue'
import Test from './components/Test.vue'

const app = createApp(App)

// 2. 调用 app 实例的 component() 方法,在全局注册 my-swiper 和 my-test 两个组件
app.component('my-swiper', Swiper)
app.component('my-test', Test)

app.mount('#app')

<!-- ------------------------------ -->

// 使用 app.component() 方法注册的全局组件,直接以标签的形式进行使用即可
// 在 main.js 中,注册了 my-swiper 和 my-test 两个全局组件
app.component('my-swiper', Swiper)
app.component('my-test', Test)

<!-- 在其他组件中,直接以标签的形式,使用刚才注册的全局组件即可 -->
<template>
    <h1>App 根组件</h1>
    <hr>
    <my-swiper></my-swiper>
    <my-test></my-test>
</template>
  • 被局部注册的组件,只能在当前注册的范围内使用

<template>
    <h1>App 根组件</h1>
    <my-swiper></my-swiper>
    <my-search></my-search>
</template>

<script>
import Search from './components/Search.vue'
export default {
    // 通过components 节点,为当前组件注册私有组件
    components: {
        'my-search': Search
    }
}
</script>

注册组件时名称的大小写

在进行组件的注册时,定义组件注册名称的方式有两种:

  1. 使用 kebab-case 命名法(俗称短横线命名法,例如 my-swiper 和 my-search)
  2. 使用 PascalCase 命名法(俗称帕斯卡命名法或大驼峰命名法,例如 MySwiper 和 MySearch)

通过 name 属性注册组件

在注册组件期间,除了可以直接提供组件的注册名称之外,还可以把组件的 name 属性作为注册后组件的名称:

样式穿透

/deep/ 是 vue2.x 中实现样式穿透的方案
在 vue3.x 中推荐使用 :deep() 替代 /deep/

:deep(.title) {
    color: pink;
}

动态样式

Class 与 Style 绑定

在实际开发中经常遇到动态操作元素样式的需求。因此,vue 运行开发者通过 v-bind 属性绑定指令,为元素动态绑定 class 属性的值和行内样式的 style 样式

动态绑定 HTML 的 class

可以通过三元表达式,动态的为元素绑定 class 的类名:

</h3 class="thin" :class="isItalic ? 'italic' : ''">MyDeep 组件</h3>
<button @click="isItalic = !isItalic">Toggle Italic</button>

data() {
    retrun {
        isItalic: true
    }
}

.thin {
    font-weight: 200;
}
.italic {
    font-style: italic;
}

以数组语法绑定 HTML 的 calss

如果元素需要动态绑定多个 class 的类名,此时可以使用数组的语法格式:

</h3 class="thin" :class="[isItalic ? 'italic' : '', isDelete ? 'delete' : '']">
    MyDeep 组件
</h3>

<button @click="isItalic = !isItalic">Toggle Italic</button>
<button @click="Delete = !Delete">Toggle Delete</button>

data() {
    retrun {
        isItalic: true,
        isDelete: false
    }
}

.thin {
    font-weight: 200;
}
.italic {
    font-style: italic;
}
.delete {
    text-decoration: line-through;
}

以对象语法绑定 HTML 的 calss

使用数组语法动态绑定 class 会导致模板结构臃肿的问题,可以使用对象语法进行简化:

</h3 class="thin" :class="classObj">MyDeep 组件</h3>
<button @click="classObj.italic = !classObj.italic">Toggle Italic</button>
<button @click="classObj.delete = !classObj.delete">Toggle Delete</button>

data() {
    retrun {
        // 对象中,属性名是 class 类名,值是布尔值
        classObj: {
            italic: true,
            delete: false
        }
    }
}

以对象语法绑定内联的 style

:style 的对象语法十分直观-看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式(camelCase)或短横线分隔(kebab-case,要用引号括起来)来命名:

<div :style="{ color: active, fontSize: fsize + 'px', 'backround-color': bgcolor }">
    qiaofugui.cn
</div>
<button @click="fsize += 1">字号 +1</button>
<button @click="fsize -= 1">字号 -1</button>

data() {
    return {
        active: 'red',
        fsize: 24,
        bgcolor: 'pink'
    }
}

props 自定义验证函数

在封装组件时,可以为 prop 属性指定自定义验证函数,从而对 props 属性的值进行更加精确的控制:

export default {
    props: {
        // 通过 “配置对象” 的形式,来定义 propD 属性的 “验证规则”
        propD: {
            type: {
                // 通过 validator 函数,对 propD 属性的值进行校验,“属性的值” 可以通过形参 value 进行接收
                validator(value) {
                // propD 属性的值,必须匹配下列字符串中的一个
                // validator 函数的返回值为 true 表示验证通过,false 表示验证失败
                return ['success', 'warning', 'danger'].indexOf(value) !== -1
                }
            },
            required: true,
            default: 'success'
        }
    }
}

自定义事件

在封装组件时,为了让组件的使用者可以监听到组件内状态的变化,需要用到组件的自定义事件

自定义事件使用 3 个步骤

在封装组件时:

  1. 声明自定义事件
  2. 触发自定义事件

在使用组件时:

  1. 监听自定义事件

声明自定义事件

开发者为自定义事件组件封装的自定义事件,必须先在 emits 节点中声明:

// 创建组件 MyCounter
<template>
    <h3>Counter 组件</h3>
    <button>+1</button>
</template>

<script>
export default {
    // my-counter 组件的自定义事件,必须事先声明待 emits 节点中
    emits: ['change']
}
</script>

触发自定义事件

emits 节点下声明的自定义事件,可以通过 this.$emit('自定义事件名称') 方法进行触发:

// 创建组件 MyCounter
<template>
    <h3>Counter 组件</h3>
    <button @click="onBtnClick">+1</button>
</template>

<script>
export default {
    data() {
        return {
            count: 1
        }
    },
    // my-counter 组件的自定义事件,必须事先声明待 emits 节点中
    emits: ['change'],
    methods: {
        onBtnClick() {
            // 当点击 +1 按钮时,调用 this.$emit() 方法,触发自定义的 change 事件
            this.$emit('change')
        }
    }
}
</script>

监听自定义事件

在使用自定义的组件时,可以通过 v-on 的形式监听自定义事件:

// 使用组件 MyCounter
<!-- 使用 v-on 指令绑定事件监听 -->
<my-counter @change="getCount"></my-counter>

methods: {
    getCount() {
        console.log('监听到了 count 值的变化')
    }
}

自定义事件传参

在调用 this.$emit() 方法触发自定义事件时,可以通过第 2 个参数为自定义事件传参:

// 创建组件 MyCounter
<template>
    <h3>Counter 组件</h3>
    <button @click="onBtnClick">+1</button>
</template>

<script>
export default {
    data() {
        return {
            count: 1
        }
    },
    emits: ['change'],
    methods: {
        onBtnClick() {
            // 触发自定义事件时,通过第 2 个参数传参
            this.$emit('change', this.count)
        }
    }
}
</script>
v-model:prpos名称、emits、$emit('update:props名称')

自定义指令

Vue3 自定义指令里面用 mounted(el) { }

全局自定义指令

const app = Vue.createApp({})

// 注册一个全局自定义指令 ‘v-focus’
app.directive('focus', {
    // 当绑定的元素插入到 DOM 中时,自动触发 mounted 函数
    mounted(el) {
        // Focus the element
        el.focus()
    }
})

updated 函数

mounted 函数只在元素第一次插入 DOM 时被调用,当 DOM 更新时 mounted 函数不会被触发。updated 函数会在每次 DOM 更新完成后被调用

app.directive('focus', {
    // 第一次插入 DOM 时触发这个函数
    mounted(el) {
        el.focus()
    },
    // 每次 DOM 更新时都会触发 updated 函数
    updated(el) {
        el.focus()
    }
})

如果 mounted 和 updated 函数中的楼及完全相同,则可以简写成一下格式:

app.directive('focus', (el) => {
    // 在 mounted 和 updated 时都会触发相同的业务处理
    el.focus()
})

在绑定指令时,可以通过 “等号” 的形式为指令绑定具体的参数值(第二个形参,binding.)

在 vue2 的项目中使用自定义指令时,【mounted -> bind】【updated -> update】

Vue3

版权属于:Joe
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
0

目录

来自 《Vue3-基础(一)》
评论

qiaofugui

博主很懒,啥都没有
188 文章数
14 评论量
3 分类数
191 页面数
已在风雨中度过 2年130天15小时26分