在 Web 的世界中从来就没有可以适配所有场景、解决所有问题的银弹。正因如此,Vue 被设计成一个灵活的、可以渐进式集成的框架。根据使用场景的不同需要,相应地有多种不同的方式来使用 Vue,以此在技术栈复杂度、开发体验和性能表现间取得最佳平衡。

Vue 不仅控制整个页面,还负责处理抓取新数据,并在无需重新加载的前提下处理页面切换。这种类型的应用通常称为单页应用 (Single-Page application,缩写为 SPA)。

参考:

知乎-黑马程序员:选择vue2还是vue3?

掘金-生若流水:盘点 Vue3 与 Vue2 的区别

掘金-Jervis_cen:浅谈Vite 原理与 Webpack比较

Vue.js:使用 Vue 的多种方式

写作社区-No Silver Bullet:Vue 进阶(三十六):created()详解

CSDN-Wzh小吴:Vue全家桶包含都有哪一些?

了解Vue

  • 虚拟DOM:没有真实的DOM操作,也叫虚拟DOM。
  • 双向数据绑定:使开发者不用再操作DOM对象。
  • 生态丰富:市场大量成熟vue.js的ui框架、常用组件,以实现快速开发。
  • 应用场景广泛:web、移动、跨平台应用开发。
  • 入门容易。

Vue Cli初始化Vue项目

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

Vue CLI 现已处于维护模式!

现在官方推荐使用 create-vue 来创建基于 Vite 的新项目。另外请参考 Vue 3 工具链指南 以了解最新的工具推荐。

参考:

Vue Cli

51CTO博客-徐同保的博客:error The engine “node“ is incompatible with this module.

博客园-金色海洋工作室:一篇文章说清 webpack、vite、vue-cli、create-vue 的区别

vue cli 版本

至于为什么打vue出现 vue cli 其实vue作为前端框架,是一个nodeJS下的一个包,即一个vue项目整体的前端工程化项目,而vue cil作为脚手架工具,仅仅只是做了一个整合各种技术栈的工具,整合了vue全家桶等依赖,这些依赖装在一个项目跟目录下的node_modules/下,具体详见:博客园-金色海洋工作室:一篇文章说清 webpack、vite、vue-cli、create-vue 的区别

1
2
 ~/ vue --version
@vue/cli 4.5.15

创建一个Vue项目模板

1
vue create hello-world		#执行创建一个项目模板

提示选择包管理器,我选择的是yarn(可能是因为我有多个包管理器的原因)

image-20221102152817865

但报了个erro

1
2
3
4
error @achrinza/node-ipc@9.2.2: The engine "node" is incompatible with this module. Expected version "8 || 10 || 12 || 14 || 16 || 17". Got "18.11.0"
error Found incompatible module.
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
ERROR command failed: yarn

直接执行

1
yarn config set ignore-engines true

成功创建Vue项目模板,cd到项目目录下执行:

1
yarn serve

浏览器访问:

image-20221102160309779

模式和环境变量

Vue2 & Vue3 都适应以下,放置于项目根目录的例如:.env.development.env.production等…

参考;

Vue Cli:模式和环境变量

CSDN-写代码的lorre:vue cli4-环境变量和模式

模式是 Vue CLI 项目中一个重要的概念。默认情况下,一个 Vue CLI 项目有三个模式:

  • development 模式用于 vue-cli-service serve
  • test 模式用于 vue-cli-service test:unit
  • production 模式用于 vue-cli-service buildvue-cli-service test:e2e

注意:

  • 一个模式可以包含多个环境变量
  • 每个模式都会将环境变量中 NODE_ENV 的值设置为模式的名称
    可以通过为 .env 文件增加后缀来设置某个模式下特有的环境变量
  • 为一个特定模式准备的环境文件 (例如 .env.production) 将会比一般的环境文件 (例如 .env) 拥有更高的优先级
  • 此外,Vue CLI 启动时已经存在的环境变量拥有最高优先级,并不会被 .env 文件覆写

NODE_ENV (模式)设置为:

  • test Vue CLI 会创建一个优化过后的,并且旨在用于单元测试的 webpack 配置,它并不会处理图片以及一些对单元测试非必需的其他资源。

  • development 创建一个 webpack 配置,该配置启用热更新,不会对资源进行 hash 也不会打出 vendor bundles,目的是为了在开发的时候能够快速重新构建。

  • production 当你运行 vue-cli-service build 命令时,无论你要部署到哪个环境,应该始终把 NODE_ENV 设置为 "production"来获取可用于部署的应用程序。

设置项目环境变量

你可以在你的项目根目录中放置下列文件来指定环境变量:

1
2
3
4
.env                # 在所有的环境中被载入
.env.local # 在所有的环境中被载入,但会被 git 忽略
.env.[mode] # 只在指定的模式中被载入
.env.[mode].local # 只在指定的模式中被载入,但会被 git 忽略

一个环境文件只包含环境变量的“键=值”对:

1
2
FOO=bar
VUE_APP_NOT_SECRET_CODE=some_value

请注意,只有 NODE_ENVBASE_URL 和以 VUE_APP_ 开头的变量将通过 webpack.DefinePlugin 静态地嵌入到客户端侧的代码中。这是为了避免意外公开机器上可能具有相同名称的私钥。

环境文件加载优先级

为一个特定模式准备的环境文件 (例如 .env.production) 将会比一般的环境文件 (例如 .env) 拥有更高的优先级。

此外,Vue CLI 启动时已经存在的环境变量拥有最高优先级,并不会被 .env 文件覆写。

.env 环境文件是通过运行 vue-cli-service 命令载入的,因此环境文件发生变化,你需要重启服务。

在客户端侧代码中使用环境变量
只有以 VUE_APP_ 开头的变量会被 webpack.DefinePlugin 静态嵌入到客户端侧的包中。你可以在应用的代码中这样访问它们:

1
console.log(process.env.VUE_APP_SECRET)

在构建过程中,process.env.VUE_APP_SECRET 将会被相应的值所取代。在 VUE_APP_SECRET=secret 的情况下,它会被替换为 “secret”。

除了 VUE_APP_* 变量之外,在你的应用代码中始终可用的还有两个特殊的变量:

NODE_ENV - 会是 “development”、”production” 或 “test” 中的一个。具体的值取决于应用运行的模式。
BASE_URL - 会和 vue.config.js 中的 publicPath 选项相符,即你的应用会部署到的基础路径。

所有解析出来的环境变量都可以在 public/index.html 中以 HTML 插值中介绍的方式使用。

示例

请参考:CSDN-写代码的lorre:vue cli4-环境变量和模式

生命周期

参考:

Vue.js-文档:生命周期选项

Vue.js:生命周期钩子

红色框中的生命周期选项均可调用

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Vue.component("demo1",{ 
data:function(){
return {
name:"",
age:"",
city:""
}
},
//其中{{}}括起来的就是代表上面return中的变量
template:"<ul><li id='name'>{{name}}</li><li>{{age}}</li><li>{{city}}</li></ul>",
//模板渲染成`html`前调用
created:function(){
this.name="唐浩益"
this.age = "12"
this.city ="杭州"
//渲染前调用,html未渲染完成,此行代码会报错["innerHTML" of null]
var x = document.getElementById("name")
console.log(x.innerHTML);
},
mounted:function(){
//渲染后调用,html渲染完成,并将变量name、age、city渲染进template,调用后就会出现打印:唐浩益"、"12"、"杭州"(列表)
var x = document.getElementById("name")/</span>/第二个命令台输出的结果<span style="font-size: 14px;">
console.log(x.innerHTML);
}
});
var vm = new Vue({
el:"#example1"
})
  • 加载逻辑

    • beforeCreate在组件实例初始化完成之后立即调用

    • created在组件实例处理完所有与状态相关的选项后调用、模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图

  • 渲染DOM

    • beforeMount在组件被挂载之前调用,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程
    • mounted在组件被挂载之后调用、模板渲染成html后调用,通常是初始化页面完成后,再对htmldom节点进行一些操作。
  • 更新DOM

    • beforeUpdate组件即将因为一个响应式状态变更而更新其 DOM 树之前调用。
    • updated在组件因为一个响应式状态变更而更新其 DOM 树之后调用
  • 卸载组件

    • beforeUnmount在一个组件实例被卸载之前调用
    • unmounted在一个组件实例被卸载之后调用

通常created使用的次数多,而mounted是在一些插件或组件的使用中进行操作。

export & import

ECMAScript模块(ESM)是在ECMAScript 6标准中引入的一种模块系统,它使用import和export等关键字来实现模块的导入和导出。尽管ESM在浏览器环境中已经得到了广泛的支持,但在Node.js中,直到最近的版本中才开始支持ESM语法。这种转变是为了使Node.js更加符合JavaScript的标准化发展,并且与浏览器环境更加一致。

vue 中的一个文件可以被了理解为一个模块。export(导出),import(导入),即ECMAScript (浏览器)模块语法,都能导出模块里的常量、函数、文件、模块等…

如果是Node.js 默认使用的是 CommonJS 模块系统,即使用 module.exportsrequire 来导出和导入模块

参考:

CSDN-疆~:vue中常用的几种import(模块、文件)引入方式,export,export default,全部/部分文件的导出/导入

掘金-何小玍:export和export default的区别

ES模块语法

export/import default

只能在一个模块中出现一次,在另一个模块 import 就不需要加{}

1
2
3
4
5
// 在某个js文件中使用export default导出变量
export default {
name: 'John',
age: 30,
};

在其他文件中导入这个默认导出的变量:

1
2
3
4
5
javascriptCopy code// 正确的导入方式
import person from './path-to-file.js';

console.log(person.name); // 输出:John
console.log(person.age); // 输出:30

使用export default时,只能将整个默认导出的对象引入,并使用指定的变量名(在这里是person)来访问对象的属性。

export/import

变量

1
2
3
4
5
6
7
8
// @/utils/tabbar.js

export const tabInfo = {
name: 'Home',
icon: 'home.png',
};

export const otherVar = 42;

在这个模块中,有一个tabInfo的常量和一个otherVar的常量。如果你只想导入tabInfo,那么你可以使用解构导入的方式:

1
2
3
4
import { tabInfo } from '@/utils/tabbar';

console.log(tabInfo.name); // 输出:Home
console.log(tabInfo.icon); // 输出:home.png

使用解构导入时,你只需要指定你感兴趣的变量名(在这里是tabInfo),而不需要导入整个模块。这样可以提高代码的可读性,并只导入需要的内容,避免了不必要的资源加载和冗余代码。

函数

导出

1
2
export function  getDefTime(dayNum) {
}
1
2
3
4
function setDefTime(dayNum) {
}
// 大括号内可包含多个
export {getDefTime}

导入

1
2
// 大括号内可包含多个
import { getDefTime } from '@/utils/tabbar';

导入css

1
import 'iview/dist/styles/iview.css';

如果是在.vue文件中那么在外面套个style

1
2
3
4
<style>
@import './test.css';

</style>

单文件组件

它被称为单文件组件 (也被称为 *.vue 文件,英文 Single-File Components,缩写为 SFC)。顾名思义,Vue 的单文件组件会将一个组件的逻辑 (JavaScript),模板 (HTML) 和样式 (CSS) 封装在同一个文件里。

Vue 单文件组件 (SFC) 规范

常用知识点

参考:

CSDN-明天也要努力:Vue中 Vue.prototype 详解及使用

Vue.prototype

main.js

1
2
// 作用是将名为$appName这个变量设置为全局可用
Vue.prototype.$appName = 'My App'

带$的作用

只是避免在组件中使用时,自己在组件中创建了相同的变量名称不会被非全局变量覆盖

1
Vue.prototype.appName = 'My App'

以下 beforeCreate 先执行 created 后执行(appName被覆盖)

1
2
3
4
5
6
7
8
9
10
11
12
new Vue({
data: {
// 啊哦,`appName` 也是一个我们定义的实例 property 名!
appName: 'The name of some other app'
},
beforeCreate: function () {
console.log(this.appName) // 先打印出局部变量:My App
},
created: function () {
console.log(this.appName) // 后打印出全局变量:The name of some other app
}
})

组件间调用

组件的name选项设置为'kqShow',这是你显式地给组件命名的结果。当你在父组件中使用kq-show标签时,这个名称kq-cart实际上就是组件的名称,它由组件的name选项决定。

全局

组件中

1
2
3
export default {
name: 'kqShow'
}

@/main.js

1
2
3
// 挂载 全局组件
import kqShow from '@/components/kq-show';
Vue.component('kqShow', kqShow);

页面中直接可以使用

1
<kq-show></kq-show>

局部

组件中

1
2
3
export default {
name: 'kqCart',
}

父级调用

1
2
3
4
5
6
7
8
9
10
11
<template>
<kq-cart></kq-cart>
</template>
<script>
...
components: {
kqGoods,
kqCart,
}
...
</script>

父子间方法调用

参考:

cnblog-柯南。道尔:vue中this.$emit的用法

父组件

父组件中声明子组件需要访问的方法@search="navToSearch"@tab="tabClick"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<rf-search-bar
@search="navToSearch"
@tab="tabClick"
title="扫一扫"
icon="iconsaomiao"
:categoryList="categoryList"
:merchantData="merchantData"
:placeholder="hotSearchDefault"
/>
...
<rf-search-bar/>

<script>
...
data() {
hotSearchDefault: '请输入关键字',
},
methods: {
navToSearch() {
this.$mRouter.push({
// stringify 字符串化
// this.search 应该是获取从子组件传过来的searchValue
route: `/pages/index/search/search?data=${JSON.stringify(this.search)}`
});
},
// 此方法id从子传参
tabClick({ id }) {
this.currentCate = id;
if (id === 0) return;
this.loading = true;
this.page = 1;
this.productLoading = true;
this.categoryProductList = [];
this.getProductList(id);
},


}
...
</script>

子组件

子组件中收到'search''tab',分别对应父组件中的navToSearchtabClick,使用this.$emit(<方法名>,[传参])调用父组件中给定的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!-- 搜索框 -->
<view class="input-box" @tap="toSearch">
...
</view>
...
<view
v-for="(item, index) in categoryList"
:key="index"
class="index-cate-item"
:class="tabCurrentIndex === index ? `text-${themeColor.name} active` : ''"
@tap.stop="tabClick(index, item.id)"
>
{{ item.title }}
</view>

<script>
export default {
props: {
placeholder: {
type: String,
default: '请输入关键字'
},
},
data() {
return {
searchValue: this.placeholder,
}
methods: {
async toSearch() {
await this.$emit('search', {
searchValue: this.searchValue
});
},

tabClick(index, id) {
this.tabCurrentIndex = index;
// 父级组件事件传递到$emit,tab是其中之一
this.$emit('tab', {
id
});
}
}
}
</script>

vue-watch监听

参考:

CSDN-页神建辑-思而后学:vue-watch监听功能(侦听器)详解&使用

filters

例如常用于:后端字段type返回数据 0、1、2,分别代表三种状态禁用、启用、处理,如何使后端返回的数据显示在前端以状态显示

使用了Vue的过滤器(Filter)功能。在模板中使用管道(|)将status的值传递给过滤器,并在过滤器中将其转换为相应的状态文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
<div>
<p>Status: {{ status | displayStatus }}</p>
</div>
</template>

<script>
export default {
data() {
return {
status: 2, // 这里假设从后端获取的状态值为2
};
},
filters: {
displayStatus(value) {
switch (value) {
case 0:
return '禁用';
case 1:
return '启用';
case 2:
return '处理';
default:
return '未知状态';
}
},
},
};
</script>