vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue命令行工具Vue-CLI

Vue命令行工具Vue-CLI图文详解(推荐!)

作者:知其黑、受其白

vue-cli 是 Vue.js 开发的标准工具,它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程,下面这篇文章主要给大家介绍了关于Vue命令行工具Vue-CLI的相关资料,需要的朋友可以参考下

阐述

vue-cli 构建一个工程的时候,发现官方文档还是不够用,需要熟练掌握 es6,而 vue 的全家桶还是都要上的。

Vue CLI 的包名称由vue-cli改成了@vue/cli。 如果你已经全局安装了旧版本的vue-cli(1.x 或 2.x),你需要先通过 npm uninstall vue-cli -g 或 yarn global remove vue-cli 卸载它。

安装新版的脚手 node 也有版本要求,Vue CLI 4.x 需要Node.jsv8.9 或更高版本 (推荐 v10 以上)。

vue全家桶

vue全家桶是基于vue开发必备的也是必学的东西,概括起来就是:

1.vue-cli项目构建工具

2.vue-router路由管理

3.vuex状态管理全局变量

4.axios,http请求工具。

5.UI 框架 element,iview,vant

最常见常用的 vue 全家桶简单的介绍一下,希望可以帮助你了解认识学会 vue 全家桶!

vue-cli

vue-cli 就是快速搭建一个 vue 项目的脚手架工具。

VueCLI是一个官方发布vue.js项目脚手架,使用 VueCLI 可以快速搭建 vue 开发环境,以及对应的 webpack 配置。

1、CLI 是 Command-Line Interface, 翻译为命令行界面, 但是俗称脚手架

2、Vue CLI是一个官方发布 vue.js 项目脚手架

3、使用 vue-cli 可以快速搭建 Vue 开发环境以及对应的 webpack 配置.

关于旧版本

Vue CLI 的包名称由 vue-cli 改成了 @vue/cli。 如果你已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先通过 npm uninstall vue-cli -gyarn global remove vue-cli 卸载它。

脚手架依赖于 node.jswebpack

Vue CLI 需要 Node.js 8.9 或更高版本 (推荐 8.11.0+)。你可以使用 nvm 或 nvm-windows 在同一台电脑中管理多个 Node 版本。

Vue CLI 的安装

Vue CLI2初始化项目:vue init webpack my-project

Vue CLI3初始化项目:vue create my-project

注意: 下面的默认安装的是 Vue CLI3 的版本,如果需要想按照 Vue CLI2 的方式初始化项目时不可以的。

由于博主的版本过低出现了切换 node 版本、反复安装操作,第二步查看 Vue Cli 需要的node 版本。版本一直请越过反复安装过程。

① 默认安装 vue/cli 脚手架 3

PS C:\Windows\system32> npm install -g @vue/cli
npm WARN deprecated subscriptions-transport-ws@0.9.19: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws    For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md
npm WARN deprecated graphql-tools@4.0.8: This package has been deprecated and now it only exports makeExecutableSchema.\nAnd it will no longer receive updates.\nWe recommend you to migrate to scoped packages such as @graphql-tools/schema, @graphql-tools/utils and etc.\nCheck out https://www.graphql-tools.com to learn what package you should use instead
npm WARN deprecated apollo-cache-control@0.14.0: The functionality provided by the `apollo-cache-control` package is built in to `apollo-server-core` starting with Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#cachecontrol for details.
npm WARN deprecated apollo-tracing@0.15.0: The `apollo-tracing` package is no longer part of Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#tracing for details
npm WARN deprecated graphql-extensions@0.15.0: The `graphql-extensions` API has been removed from Apollo Server 3. Use the plugin API instead: https://www.apollographql.com/docs/apollo-server/integrations/plugins/
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
C:\Program Files\nodejs\vue -> C:\Program Files\nodejs\node_modules\@vue\cli\bin\vue.js

> core-js-pure@3.22.0 postinstall C:\Program Files\nodejs\node_modules\@vue\cli\node_modules\core-js-pure
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js:
> https://opencollective.com/core-js
> https://patreon.com/zloirock
> bitcoin: bc1qlea7544qtsmj2rayg0lthvza9fau63ux0fstcz

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> @apollo/protobufjs@1.2.2 postinstall C:\Program Files\nodejs\node_modules\@vue\cli\node_modules\@apollo\protobufjs
> node scripts/postinstall

npm WARN node-fetch@2.6.7 requires a peer of encoding@^0.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.5.7 requires a peer of bufferutil@^4.0.1 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.5.7 requires a peer of utf-8-validate@^5.0.2 but none is installed. You must install peer dependencies yourself.

+ @vue/cli@5.0.4
added 880 packages from 531 contributors in 130.475s

结束

② 默认安装失败,解决mode版本问题

安装之后,你就可以在命令行中访问 vue 命令。

检查其版本是否正确:

PS C:\Windows\system32> vue --version
You are using Node v11.15.0, but this version of @vue/cli requires Node ^12.0.0 || >= 14.0.0.
Please upgrade your Node version.

您使用的是 Node v11.15.0,但是这个版本的 @vue/cli 需要 Node ^12.0.0 || >= 14.0.0。
请升级您的节点版本。

PS C:\Windows\system32>

③ nvm下载太慢问题解决

由于 nvm 默认的下载地址 http://nodejs.org/dist/ 是外国外服务器,国内很慢可以使用淘宝的镜像。

where nvm 找到 nvm 安装路径

找到 settings.txt 文件

将下面这两句话复制到settings.txt,并保存

node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/

④ 安装 Node ^12.0.0

PS C:\Windows\system32> nvm install 12.0.0
Downloading node.js version 12.0.0 (64-bit)...
Complete
Creating C:\Users\ASUS\AppData\Roaming\nvm\temp

Downloading npm version 6.9.0... Complete
Installing npm v6.9.0...

Installation complete. If you want to use this version, type

nvm use 12.0.0

PS C:\Windows\system32> nvm use 12.0.0
Now using node v12.0.0 (64-bit)

PS C:\Windows\system32> nvm list

    14.17.6
  * 12.0.0 (Currently using 64-bit executable)
    11.15.0  此版本主项目
PS C:\Windows\system32>

⑤ 从新安装 VueCli 脚手架 3

PS C:\Windows\system32> npm install -g @vue/cli
npm WARN deprecated subscriptions-transport-ws@0.9.19: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws    For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md
npm WARN deprecated graphql-tools@4.0.8: This package has been deprecated and now it only exports makeExecutableSchema.\nAnd it will no longer receive updates.\nWe recommend you to migrate to scoped packages such as @graphql-tools/schema, @graphql-tools/utils and etc.\nCheck out https://www.graphql-tools.com to learn what package you should use instead
npm WARN deprecated apollo-cache-control@0.14.0: The functionality provided by the `apollo-cache-control` package is built in to `apollo-server-core` starting with Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#cachecontrol for details.
npm WARN deprecated apollo-tracing@0.15.0: The `apollo-tracing` package is no longer part of Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#tracing for details
npm WARN deprecated graphql-extensions@0.15.0: The `graphql-extensions` API has been removed from Apollo Server 3. Use the plugin API instead: https://www.apollographql.com/docs/apollo-server/integrations/plugins/
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
C:\Program Files\nodejs\vue -> C:\Program Files\nodejs\node_modules\@vue\cli\bin\vue.js

> core-js-pure@3.22.0 postinstall C:\Program Files\nodejs\node_modules\@vue\cli\node_modules\core-js-pure
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js:
> https://opencollective.com/core-js
> https://patreon.com/zloirock
> bitcoin: bc1qlea7544qtsmj2rayg0lthvza9fau63ux0fstcz

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> @apollo/protobufjs@1.2.2 postinstall C:\Program Files\nodejs\node_modules\@vue\cli\node_modules\@apollo\protobufjs
> node scripts/postinstall

npm WARN node-fetch@2.6.7 requires a peer of encoding@^0.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.5.7 requires a peer of bufferutil@^4.0.1 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.5.7 requires a peer of utf-8-validate@^5.0.2 but none is installed. You must install peer dependencies yourself.

+ @vue/cli@5.0.4
added 880 packages from 531 contributors in 81.975s
安装结束

查看 vue 版本,及验证是否安装正确。

PS C:\Windows\system32> vue --version
@vue/cli 5.0.4
PS C:\Windows\system32>

④ 拉取 2.x 模板 (旧版本)

Vue CLI >= 3 和旧版使用了相同的 vue 命令,所以 Vue CLI 2 (vue-cli) 被覆盖了。

如果你仍然需要使用旧版本的 vue init 功能,你可以全局安装一个桥接工具:

PS C:\Windows\system32> npm install -g @vue/cli-init
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
+ @vue/cli-init@5.0.4
added 259 packages from 231 contributors in 38.328s
PS C:\Windows\system32>

vue init 的运行效果将会跟 vue-cli@2.x 相同。

创建项目提示,原因上面安装已经提示命令都为弃用状态。

PS E:\node> vue init webpack vue-cli2-test

  Command vue init requires a global addon to be installed.
  Please run undefined @vue/cli-init and try again.
  
  命令 vue init 需要安装全局插件。
  请运行 undefined @vue/cli-init 并重试。

PS E:\node>

⑤ 安装vue指定版本

【前端开发】Vue-CLI4 &Vue-CLI3 与Vue-CLI2 的区别

1、安装:

Vue-CLI2:

npm install -g vue-cli 或 cnpm install -g vue-cli

Vue-CLI最新版本:

npm install -g @vue/cli 或 cnpm install -g @vue/cli

2、卸载

Vue-CLI2:

npm uninstall -g vue-cli 或 cnpm uninstall -g vue-cli

Vue-CLI最新版本:

npm uninstall -g @vue/cli 或 cnpm uninstall -g @vue/cli

指定版本安装

可以安装:2.6.0 版本
npm install -g vue-cli@2.6
可以安装:2.6.0 版本
cnpm install -g vue-cli@v2.6.*
卸载vue
cnpm uninstall -g vue-cli

cdn 链接

<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>

https://unpkg.com/browse/vue@2.6.14/dist/
选择vue版本
https://unpkg.com/browse/vue@2.6.14/dist/vue.min.js

⑥ 博主node版本

改 vue 版本

PS C:\WINDOWS\system32> npm install vue-cli -g
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
C:\Program Files\nodejs\vue-init -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue-init
C:\Program Files\nodejs\vue-list -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue-list
C:\Program Files\nodejs\vue -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue
+ vue-cli@2.9.6
added 244 packages from 229 contributors and updated 1 package in 22.77s



PS C:\WINDOWS\system32> vue -V
2.9.6
PS C:\WINDOWS\system32>

如何查看 Vue项 目 vue 的版本号:

如果是用 vue-cli 创建的项目,则找到项目根目录下的 "package.json" 文件。

初始化项目

① vue init命令讲解

用 vue init 命令来初始化项目,具体使用方法如下:

vue init <template-name> <project-name>

init:表示要用 vue-cli 来初始化项目

<template-name>:表示模板名称,vue-cli 官方提供的 5 种模板:

1、webpack:

一个全面的 webpack+vue-loader 的模板,功能包括热加载,linting,检测和CSS扩展。

2、webpack-simple:

一个简单 webpack+vue-loader 的模板,不包含其他功能,让你快速的搭建 vue 的开发环境。

3、browserify:

一个全面的 Browserify+vueify 的模板,功能包括热加载,linting,单元检测。

4、browserify-simple:

一个简单 Browserify+vueify 的模板,不包含其他功能,让你快速的搭建 vue 的开发环境。

5、simple:

一个最简单的单页应用模板。

<project-name>:标识项目名称,用户根据自己的项目来起名字。

② 项目初始化

在实际开发中,一般都会使用 webpack 这个模板,命令使用如下:

第一步操作:

PS E:\node> vue init webpack vue-cli296

? Project name (vue-cli296)

Project name:项目名称 ,默认为初始化建项目的名称 vue-cli296,不需要直接回车

第二步操作:

 Project description (A Vue.js project)

Project description:项目描述,默认为A Vue.js project,不需要直接回车

Author (cwgqmxy <1157818690@qq.com>)

Author:作者,如果有配置 git 的作者,自动会读取。直接回车

第三步操作:

两个选项,Runtime + Compiler 和 Runtime-only:

· Runtime + Compiler: recommended for most users

(运行程序+编译器:推荐给大多数用户)

· Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specificHTML) are ONLY allowed in .vue files - render functions are required elsewhere

(仅运行程序: 比上面那种模式轻大约 6KB min+gzip,但是 template (或任何特定于vue的html)只允许在.vue文件中使用——其他地方用需要 render 函数)

区别

1、runtime-only 比 runtime-compiler 轻 6kb

2、runtime-only 运行更快

3、runtime-only 其实只能识别 render 函数,不能识别 template,.vue 文件中的也是被 vue-template-compiler 翻译成了 render 函数,所以只能在 .vue 里写 template。

两种模式生成的 脚手架 即(代码模板)其实区别只有在 main.js 中,其他都是一样的:

可以发现一个 是用 template + component 而另一个 则是 用 render 函数。

第四步操作:

Install vue-router? (Y/n)

Install vue-router?

是否安装vue的路由插件,需要安装,选择Y

第五步操作:

Use ESLint to lint your code? (Y/n)

输入 Y
Pick an ESLint preset:选择分支风格

选项有三个(博主选了第一个)
1.standard(https://github.com/feross/standard) js的标准风格
2.Airbnb(https://github.com/airbnb/javascript) JavaScript最合理的方法,这个github地址说是JavaScript最合理的方法
3.none (configure it yourself) 自己配置

Use ESLint to lint your code?

是否用 ESLint 来限制你的代码错误和风格。不需要输入n,需要选择y,如果是大型团队开发,最好是进行配置。

第六步操作:

Set up unit tests (Y/n)

是否需要安装单元测试工具,不需要输入n,需要选择y

第七步操作:

Setup e2e tests with Nightwatch? (Y/n)

是否安装E2E测试框架NightWatch(E2E,也就是End To End,就是所谓的“用户真实场景”。

第八步操作:

Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys)

(译:项目创建后是否要为你运行 “npm install”? 这里选择包管理工具)

选项有三个
yes,use npm(使用npm)
yes,use yarn(使用yarn)
no,I will handle that myself(自己配置安装包)

开始创建了项目,初始化完成之后会出现以下信息,表示操作成功。

PS E:\node> vue init webpack vue-cli296

? Project name vue-cli296
? Project description A Vue.js project
? Author cwgqmxy <1157818690@qq.com>
? Vue build runtime
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

   vue-cli · Generated "vue-cli296".

# Installing project dependencies ...
# ========================

npm WARN deprecated babel-eslint@8.2.6: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
npm WARN deprecated eslint-loader@1.9.0: This loader has been deprecated. Please use eslint-webpack-plugin
npm WARN deprecated extract-text-webpack-plugin@3.0.2: Deprecated. Please use https://github.com/webpack-contrib/mini-css-extract-plugin
npm WARN deprecated html-webpack-plugin@2.30.1: out of support
npm WARN deprecated browserslist@2.11.3: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
npm WARN deprecated uglify-es@3.3.9: support for ECMAScript is superseded by `uglify-js` as of v3.13.0
npm WARN deprecated bfj-node4@5.3.1: Switch to the `bfj` package for fixes and new features!
npm WARN deprecated core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
npm WARN deprecated chokidar@2.1.8: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated flatten@1.0.3: flatten is deprecated in favor of utility frameworks such as lodash.
npm WARN deprecated browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
npm WARN deprecated svgo@0.7.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
npm WARN deprecated circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated

> core-js@2.6.12 postinstall E:\node\vue-cli296\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)

> ejs@2.7.4 postinstall E:\node\vue-cli296\node_modules\ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)

> es5-ext@0.10.60 postinstall E:\node\vue-cli296\node_modules\es5-ext
>  node -e "try{require('./_postinstall')}catch(e){}"

#
# Fatal error in , line 0
# Check failed: U_SUCCESS(status).
#
#
#
#FailureMessage Object: 000000E8857BCE10[            ......] / postinstall: info lifecycle es5-ext@0.10.60~postinstall: npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\watchpack-chokidar2\node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\webpack-dev-server\node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

npm ERR! Maximum call stack size exceeded

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2022-04-19T08_59_35_781Z-debug.log

Running eslint --fix to comply with chosen preset rules...
# ========================

> vue-cli296@1.0.0 lint E:\node\vue-cli296
> eslint --ext .js,.vue src "--fix"


# Project initialization finished!
# ========================

To get started:

  cd vue-cli296
  npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

PS E:\node>

③ 目录结构详解

④ 运行项目

环境崩溃了,从新装node环境。

npm 是什么东东?

npm其实是Node.js的包管理工具(package manager)。

为啥我们需要一个包管理工具呢?

因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。

(http://caibaojian.com/npm/all.html)

讲了这么多,npm究竟在哪?

其实npm已经在Node.js安装的时候顺带装好了。我们在命令提示符或者终端输入npm -v,

node 安装适合小白

1 去node官网下载

中文官方网址:http://nodejs.cn/

下载网址:http://nodejs.cn/download/

官方网址:https://nodejs.org/en/

2 下载完成后双击安装包,跳出安装弹窗,点击Next

以下一路 Next

               node.js runtime:node 运行环境
               orepack manager:npm 包管理
Online documentation shortcuts:在线文件快捷方式
                   Add to Path:添加路径
              corepack manager:核心包管理

不用打钩,如果打了 √ 会把 node 所有的工具都下载,需要很久,以后要什么工具,直接npm下载。

安装好啦

环境路径已经自动设置好了

可以去 cmd 窗口中查看安装 node 和 npm 的版本号。

从新来过

上面环境崩溃了,从新搭建的环境。

PS E:\node> node -v
v11.15.0
PS E:\node>

vue-cli 安装

vue-cli是vue官方出品的快速构建单页应用的脚手架,里面集成了webpack,npm,nodejs,babel,vue,vue-router。

PS E:\node> npm install vue-cli -g
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
C:\Program Files\nodejs\vue-init -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue-init
C:\Program Files\nodejs\vue -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue
C:\Program Files\nodejs\vue-list -> C:\Program Files\nodejs\node_modules\vue-cli\bin\vue-list
+ vue-cli@2.9.6
added 245 packages from 230 contributors in 27.375s
PS E:\node>
PS E:\node> vue --version
2.9.6
PS E:\node>

vue-cli 项目初始化

PS E:\node> vue init webpack vue296

? Project name vue296
? Project description A Vue.js project
? Author cwgqmxy <1157818690@qq.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

   vue-cli · Generated "vue296".


# Installing project dependencies ...
# ========================

npm WARN deprecated babel-eslint@8.2.6: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
npm WARN deprecated eslint-loader@1.9.0: This loader has been deprecated. Please use eslint-webpack-plugin
npm WARN deprecated extract-text-webpack-plugin@3.0.2: Deprecated. Please use https://github.com/webpack-contrib/mini-css-extract-plugin
npm WARN deprecated html-webpack-plugin@2.30.1: out of support
npm WARN deprecated browserslist@2.11.3: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
npm WARN deprecated uglify-es@3.3.9: support for ECMAScript is superseded by `uglify-js` as of v3.13.0
npm WARN deprecated bfj-node4@5.3.1: Switch to the `bfj` package for fixes and new features!
npm WARN deprecated chokidar@2.1.8: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated flatten@1.0.3: flatten is deprecated in favor of utility frameworks such as lodash.
npm WARN deprecated browserslist@1.7.7: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.
npm WARN deprecated svgo@0.7.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
npm WARN deprecated circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated

> core-js@2.6.12 postinstall E:\node\vue296\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> ejs@2.7.4 postinstall E:\node\vue296\node_modules\ejs
> node ./postinstall.js

Thank you for installing EJS: built with the Jake JavaScript build tool (https://jakejs.com/)


> es5-ext@0.10.60 postinstall E:\node\vue296\node_modules\es5-ext
>  node -e "try{require('./_postinstall')}catch(e){}"


> uglifyjs-webpack-plugin@0.4.6 postinstall E:\node\vue296\node_modules\webpack\node_modules\uglifyjs-webpack-plugin
> node lib/post_install.js

npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\watchpack-chokidar2\node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\webpack-dev-server\node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

added 1395 packages from 715 contributors in 76.245s


Running eslint --fix to comply with chosen preset rules...
# ========================


> vue296@1.0.0 lint E:\node\vue296
> eslint --ext .js,.vue src "--fix"


# Project initialization finished!
# ========================

To get started:

  cd vue296
  npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

PS E:\node>

cd 命令进入到项目目录

npm run dev

成功页面

package.json

{
  "name": "vue296",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "cwgqmxy <1157818690@qq.com>",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js"
  },
  "dependencies": {
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^8.2.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-loader": "^7.1.1",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-plugin-transform-vue-jsx": "^3.5.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "chalk": "^2.0.1",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^4.15.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^3.0.1",
    "eslint-plugin-vue": "^4.0.0",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "node-notifier": "^5.1.2",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "portfinder": "^1.0.13",
    "postcss-import": "^11.0.0",
    "postcss-loader": "^2.0.8",
    "postcss-url": "^7.2.1",
    "rimraf": "^2.6.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

项目结构

一个 vue-cli 的项目结构如下,其中 src 文件夹是需要掌握,其余了解即可。

文件夹目录如下:

1、build目录(webpack配置)

build 文件主要是 webpack 的配置,目录详情如下:

2、config目录(vue项目配置目录)

config 文件主要是项目相关配置,常用的就是当端口冲突时配置监听端口,打包输出路径及命名等,目录详情如下:

3、node_modules(项目依赖包)

node_modules 里面是项目依赖包,其中包括很多基础依赖,自己也可以根据需要安装其他依赖。安装方法打开命令工具,进入项目目录,输入 npm install [依赖包名称],回车。

安装依赖:npm i

在两种情况下我们会自己去安装依赖:

》项目运行缺少该依赖包

》安装插件:如 vuex

PS:有时会安装指定依赖版本,需在依赖包名称后加上版本号信息,

npm install vue-loader@11.1.4

src 项目核心文件讲解

核心文件目录前面已经说明了,下面重点讲解 index.html,main.js,App.vue,routerindex.js,HelloWorld.vue

1、index.html(主页)

index.html 为项目的主页,跟其他 html 一样,但一般只定义一个空的根节点,在 main.js 里面定义的实例将挂载在根节点下,内容都通过 vue 组件来填充。

说明如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>my-vue-demo</title>
  </head>
  <body>
      <!-- 定义的vue实例将挂载在#app节点下 -->
    <div id="app"></div>
  </body>
</html>

2、main.js(入口文件)

main.js 为项目的入口文件,即单入口,主要是引入 vue 框架,根组件及路由设置,并且定义 vue 实例,说明如下:

// 引入vue框架
import Vue from 'vue'
// 引入根组件
import App from './App'
// 引入路由配置
import router from './router'

// 关闭生产模式下给出的提示
Vue.config.productionTip = false

// 定义实例
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

3、App.vue(根组件)

一个 vue 页面通常由三部分组成:

模板 (template)

js (script)

样式 (style)

说明如下:

<!-- 模板 --><template> <div id="app"> <img src="./assets/logo.png"> <router-view/> </div></template><!-- js代码 --><script>export default {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> name: 'App'}</script><!-- css样式 --><style>#app {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}</style>

[ template-模板 ]

(1) 模板只能包含一个父节点,也就是说顶层的 div 只能有一个

(如上图,父节点为 #app 的 div,其没有兄弟节点)

(2)是子路由视图插槽,后面的路由页面都显示在此处,相当于 iframe

【script-JS代码】

vue 通常用 es6 来写,用 export default 导出,其下面可以包含数据 data,生命周期 ( mounted 等),方法( methods )等。

【style-CSS样式】

样式通过 style 标签 <style></style> 包裹,默认是影响全局的,如需定义作用域只在该组件下起作用,需在标签上加 scoped,<style scoped></style>

引入外部CSS示例:

<style>
    import './assets/css/public.css'
</style>

4、router(路由配置)

router文件夹下,有一个 index,js 的路由配置文件,

说明如下:

// 引入vue框架
import Vue from 'vue'
// 引入vue-router路由依赖
import Router from 'vue-router'
// 引入页面组件,命名为HelloWorld
import HelloWorld from '@/components/HelloWorld'

// 使用路由依赖
Vue.use(Router)

// 定义路由配置
export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

5、HelloWorld.vue(页面组件)

最熟悉的 HelloWorld 输出,说明如下:

<template>
  <div>
    <!-- 输出变量 -->
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  // 定义页面名称,可以不要
  name: 'HelloWorld',
  data () {
    return {
      // 定义变量
      msg: 'HelloWorld'
    }
  }
}
</script>

<style scoped>
h1 {
  font-size: 16px;
  font-weight: normal;
}
</style>

网页 CDN 引入 vue@2.6.14 示例

<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>

https://unpkg.com/browse/vue@2.6.14/dist/
选择vue版本
https://unpkg.com/browse/vue@2.6.14/dist/vue.min.js
<!--第一步:创建文件夹及html文件-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之Helloworld</title>
    <!--第二步:引入Vue库-->
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>
    <!--第三步:创建一个Div-->
    <div id="app">
        <!--Vue的模板的绑定数据的方法,用两对花括号进行绑定Vue中的数据对象的属性 -->
        {{message}}
    </div>

    <!--第四步:创建Vue的对象,并把数据绑定到上面创建好的div上去。-->
    <script type="text/javascript">
        var app=new Vue({ // 创建Vue对象。Vue的核心对象。
            el:'#app', // el属性:把当前Vue对象挂载到 div标签上,#app是id选择器
            data:{    // data: 是Vue对象中绑定的数据
                message:'hello Vue!' // message 自定义的数据
            }
        })
    </script>
</body>
</html>

内部指令

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之Helloworld</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
    <style type="text/css">
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
<div id="app">
    <!-- v-if -->
    <div v-if="isLogin">你好</div>
    <!-- v-else -->
    <div v-else>请登录后操作</div>
    <!-- v-show -->
    <div v-show="isLogin">你好</div>
    <!-- v-else-if -->
    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else-if="type === 'C'">C</div>
    <div v-else>Not A/B/C</div>
    
    <!-- v-for基本使用 -->
    <ul>
        <li v-for="item in items">
            {{item}}
        </li>
    </ul>
    
    <!-- v-for高级使用 -->
    <ul>
        <li v-for="(value, key, index) in object">
            {{ index }}. {{ key }} - {{ value }}
        </li>
    </ul>
    
    <!-- v-text -->
    <div v-text="message"></div>
    
    <!-- v-html -->
    <div v-html="msgHtml"></div>
    
    <!-- v-on部分 -->
    <div>本场比赛得分:{{count}}</div>
    
    <!-- 常规写法 -->
    <button v-on:click="add">加分</button>
    <!-- @缩写 -->
    <button @click="add">加分</button><br/>
    
    <!-- v-model input -->
    <input type="text" v-model="message">
    <br/>
    
    <!-- v-model textarea -->
    <textarea  cols="30" rows="10" v-model="message"></textarea>
    <br/>
    
    <!-- v-model checkbox -->
    <input type="checkbox" id="first" value="1" v-model="status">
    <label for="first">有效</label>
    <input type="checkbox" id="second" value="2" v-model="status">
    <label for="second">无效</label>
    <div>状态:{{status}}</div>
    
    <!-- v-model radio -->
    <input type="radio" id="one" value="男" v-model="sex">
    <label for="one">男</label>
    <input type="radio" id="two" value="女" v-model="sex">
    <label for="one">女</label>
    <div>性别:{{sex}}</div>
    
    <!-- v-model select -->
    <select v-model="selected">
        <option disabled value="">请选择</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
    </select>
    <div>Selected: {{ selected }}</div>
    
    <!-- v-model select -->
    <img v-bind:src="imgSrc"  width="200px"><br/>
    <img :src="imgSrc"  width="200px"><br/>
    
    <!-- v-pre -->
    <div v-pre>{{message}}</div>
    
    <!-- v-cloak -->
    <div v-cloak>{{message}}</div>
    
    <!-- v-pre -->
    <div v-once>第一次绑定的值:{{message}}</div>
    
</div>

<script type="text/javascript">
var app=new Vue({
    el:'#app',
    data:{
        isLogin: false,
        type: 'A',
        items:[20,23,18,65],
        object: {
            firstName: 'John',
            lastName: 'Doe'
        },
        message: 'hello Vue',
        msgHtml: '<h2>hello Vue!</h2>',
        count: 1,
        status: [],
        sex: '男',
        selected: '',
        imgSrc:'http://liangxinghua.com/uploads/image/20180709/1531106987.png'
    },
    methods: {
        add() {
            this.count++;
        }
    }
})
</script>
</body>
</html>

(1)v-if

<div v-if="isLogin">你好</div>

(2)v-else

<div v-else>请登录后操作</div>

(3)v-show

<div v-show="isLogin">你好</div>

(4)v-else-if

<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>

(5)v-if 与 v-show 的区别

v-if: 在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,开销较高,在运行时条件很少改变时使用。

v-show:调整css dispaly属性,开销较小,在常频繁地切换时使用。

(6)v-for

(1)基本用法

<!-- 模板 -->
<div id="app">
    <ul>
        <li v-for="item in items">
            {{item}}
        </li>
    </ul>
</div>

<!--JS代码 -->
<script type="text/javascript">
    var app=new Vue({
        el:'#app',
        data:{
            items:[20,23,18,65]
        }
    })
</script>

(2)对象遍历

参数: 第一个为值,第二个为键名,第三个为索引

<!-- 模板 -->
<div id="app">
    <ul>
        <li v-for="(value, key, index) in object">
        {{ index }}. {{ key }} - {{ value }}
        </li>
    </ul>
</div>

<!--JS代码 -->
<script type="text/javascript">
    var app=new Vue({
        el:'#app',
        data:{
            object: {
                firstName: 'John',
                lastName: 'Doe'
            }
        }
    })
</script>

(7)v-text

{{xxx}} 取值有个弊端,当网速很慢或 javascript 出错时,会在页面显示 {{xxx}},Vue 提供的 v-text 可以解决这个问题。

<div>{{ message }}</div>
<!-- 和下面的一样 -->
<div v-text="message"></div>

(8)v-html

用于输出 html 代码

<span v-html="msgHtml"></span><span v-html="msgHtml"></span>

(9)v-on

(1)常规用法

// html
<div>本场比赛得分:{{count}}</div>
<button v-on:click="add">加分</button>

// JS
data:{
    count: 1
},
methods: {
    add() {
        this.count++;
    }
}

(2)缩写

<button @click="add">加分</button>

指令详情的更多用法参照 v-on 官方 API

(10)v-model

以下的 model 都需要在 data 中声明初始值:

data: {
	message: 'hello Vue',
    count: 1,
    status: [],
    sex: '男',
    selected: ''
}

(1)input

(2)textarea

<input type="text" v-model="message">
<textarea  cols="30" rows="10" v-model="message"></textarea>

(3)checkbox

<input type="checkbox" id="first" value="1" v-model="status">
<label for="first">有效</label>

<input type="checkbox" id="second" value="2" v-model="status">
<label for="second">无效</label>

<div>状态:{{status}}</div>

(4)radio

<input type="radio" id="one" value="男" v-model="sex">
<label for="one">男</label>

<input type="radio" id="two" value="女" v-model="sex">
<label for="one">女</label>

<div>性别:{{sex}}</div>

(5)select

<select v-model="selected">
    <option disabled value="">请选择</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
</select>
<div>Selected: {{ selected }}</div>

(11)v-bind

用于处理 html 标签的动态属性,即动态赋值。

(1)常规用法

// html
<img v-bind:src="imgSrc"  width="200px">

// js
data: {    
    imgSrc:'http://liangxinghua.com/uploads/image/20180709/1531106987.png'
}

(2)缩写

<img :src="imgSrc"  width="200px">

指令详情的更多用法参照 v-bind 官方 API

(12)v-pre

在模板中跳过 vue 的编译,直接输出原始值,如果在标签中加入 v-pre 就不会输出 vue 中的data 值了。

<div v-pre>{{message}}</div>

(13)v-cloak

在 vue 渲染完指定的整个 DOM 后才进行显示。它必须和 CSS 样式一起使用。

// css
[v-cloak] {
    display: none;
}

// html
<div v-cloak>{{message}}</div>

(14)v-once

只显示 DOM 第一次渲染的值,以后不改变了

<div v-once>第一次绑定的值:{{message}}</div>

生命周期

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之Helloworld</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>
    
<div id="app">
    {{message}}
</div>

<script type="text/javascript">
var app=new Vue({
    el:'#app',
    data:{
        message:'hello Vue!'
    },
    beforeCreate: function () {
        console.group('beforeCreate 创建前状态===============》');
        console.log("%c%s", "color:red" , "el      : " + this.$el); //undefined
        console.log("%c%s", "color:red","data    : " + this.$data); //undefined 
        console.log("%c%s", "color:red","message: " + this.message)  
    },
    created: function () {
        console.group('created 创建完毕状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el); //undefined
        console.log("%c%s", "color:red","data    : " + this.$data); //已被初始化 
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化
    },
    beforeMount: function () {
        console.group('beforeMount 挂载前状态===============》');
        console.log("%c%s", "color:red","el      : " + (this.$el)); //已被初始化
        console.log(this.$el);
        console.log("%c%s", "color:red","data    : " + this.$data); //已被初始化  
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
    },
    mounted: function () {
        console.group('mounted 挂载结束状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el); //已被初始化
        console.log(this.$el);     
        console.log("%c%s", "color:red","data    : " + this.$data); //已被初始化
        console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
    },
    beforeUpdate: function () {
        console.group('beforeUpdate 更新前状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el);
        console.log(this.$el);    
        console.log("%c%s", "color:red","data    : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
    },
    updated: function () {
        console.group('updated 更新完成状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el);
        console.log(this.$el); 
        console.log("%c%s", "color:red","data    : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
    },
    beforeDestroy: function () {
        console.group('beforeDestroy 销毁前状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el);
        console.log(this.$el);     
        console.log("%c%s", "color:red","data    : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message); 
    },
    destroyed: function () {
        console.group('destroyed 销毁完成状态===============》');
        console.log("%c%s", "color:red","el      : " + this.$el);
        console.log(this.$el);  
        console.log("%c%s", "color:red","data    : " + this.$data); 
        console.log("%c%s", "color:red","message: " + this.message)
    }
})
</script>
</body>
</html>

生命周期表格

周期说明
beforeCreate在实例初始化之后,数据观测和事件配置之前被调用
created在实例创建完成后被立即调用,完成数据观测,属性和方法的运算,初始化事件,$el属性未见
beforeMount在挂载开始之前被调用:相关的 render 函数首次被调用,只在虚拟DOM生成HTML
mounted在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互
beforeUpdate在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程
updated在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用
activatedkeep-alive 组件激活时调用
deactivatedkeep-alive 组件停用时调用
beforeDestroy在实例销毁之前调用。实例仍然完全可用
destroyed在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用

生命周期图解

阶段一:创建和挂载

beforecreated:el 和 data 并未初始化
      created:完成了 data 数据的初始化,el没有
  beforeMount:完成了 el 和 data 初始化
     mounted :完成挂载

阶段二:更新

在 chrome console 执行以下命令:

app.message= 'yes !! I do';

beforeUpdate:虚拟 DOM 中根据 data 变化去更新 html
     updated:将虚拟 DOM 更新完成的 HTML 更新到页面中

阶段三:销毁

在 chrome console 执行以下命令:

app.$destroy();

beforeDestroy:销毁之前调用
    destroyed:销毁之后调用,之后再执行app.message= ‘hello vue’,页面不会同步更新。

常用选项

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之Helloworld</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>
    
<div id="app">
    {{message}}
    <div>价格: {{newPrice}}</div>
    <div>数字: {{count}}</div>
    <div><button @click="add(2)">add</button></div>
    <div><input v-model="question"></div>
    <div>过滤: {{filtera | filterA}}</div>
</div>

<script type="text/javascript">
// 额外临时加入时,用于显示日志
var addLog={
    updated:function(){
        console.log("数据放生变化,变化成"+this.count+".");
    }
}

// 扩展
var extendObj ={
    created: function(){
        console.log("我是被扩展出来的");
    }
}

// 实例化vue
var app = new Vue({
    // 挂载实例
    el:'#app',
    // 页面数据初始化,字符,对象、数组
    data:{
        message: 'hello Vue!',
        price: 100,
        count: 100,
        question: '',
        filtera: 'abc'
    },
    // 计算属性:主要是对原数据进行改造输出。
    // 改造输出:包括格式化数据(价格,日期),大小写转换,排序,添加符号
    computed: {
        newPrice () {
            return '¥' + this.price + '元';
        }
    },
    // 方法声明:用于绑定html中的方法
    methods:{
        add (num) {
            this.count += num;
        }
    },
    // data属性监听器, 作用v-model
    watch: {
        question(val, oldVal) {
            console.log('new: %s, old: %s', val, oldVal);
        }
    },
    // 过滤器,通常格式化字符,使用传值
    filters: {
        filterA(value) {
            return value.toUpperCase();
        }
    },
    // 混入,作用:减少代码污染、减少代码量、实现代码重用
    mixins: [addLog],
    // 扩展
    extends: extendObj
})
</script>
</body>
</html>

1、computed 计算属性、改造输出

计算属性:主要是对原数据进行改造输出。

改造输出:包括格式化数据(价格,日期),大小写转换,排序,添加符号。

computed: {
    newPrice () {
        return '¥' + this.price + '元';
    }
}

2、methods 用于绑定 html 中的事件对应的方法

方法属性:用于绑定 html 中的事件对应的方法

methods:{
    add (num) {
        this.count += num;
    }
}

3、watch 数据变化监听器

数据变化监听器:主要用于监测 data 中的数据变化, v-model 生效

watch: {
    question(val, oldVal) {
        console.log('new: %s, old: %s', val, oldVal);
    }
}

4、filters 过滤器:通常格式化字符,使用传值

filters: {
    filterA(value) {
        return value.toUpperCase();
    }
}

5、mixins 实现代码重用

混入:用于减少代码污染、减少代码量、实现代码重用

// 额外临时加入时,用于显示日志
var addLog={
    updated:function(){
        console.log("数据放生变化,变化成"+this.count+".");
    }
}

// 实例化vue
var app = new Vue({
    // 挂载实例
    el:'#app',
    // 页面数据初始化,字符,对象、数组
    data:{
        count: 100
    },
    // 混入
    mixins: [addLog]
})

6、extends 扩展:对构造器进行扩展

// 扩展
var extendObj ={
    created: function(){
        console.log("我是被扩展出来的");
    }
}

// 实例化vue
var app = new Vue({
    // 挂载实例
    el:'#app',
    // 页面数据初始化,字符,对象、数组
    data:{
    },
    // 扩展
    extends: extendObj
})

实例事件

vue 有实例属性,实例方法,实例事件,前两个跟选项类似,不是很常用,这次只讲实例事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之Helloworld</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>

<div id="app">
    <div>数字:{{count}}</div>
    <button onclick="reduce()">on调用</button>
    <button onclick="reduceOnce()">once调用</button>
    <button onclick="off()">off调用</button>
</div>

<script type="text/javascript">
var app = new Vue({
    el:'#app',
    data:{
        count: 1
    }
})

// $on 在构造器外部添加事件
app.$on('reduce',function(){
    console.log('执行了reduce()');
    this.count--;
});

// 调用
function reduce() {
    // 事件调用
    console.log('emit事件调用');
    app.$emit('reduce');
}

// $once执行一次的事件
app.$once('reduceOnce',function(){
    console.log('只执行一次的方法');
    this.count--;
});

// 调用
function reduceOnce() {
    app.$emit('reduceOnce');
}

// 关闭事件
function off(){
    console.log('关闭事件');
    app.$off('reduce');
}
</script>
</body>
</html>

1、$on(在构造器外部添加事件)

$on 接收两个参数,第一个参数是调用时的事件名称,第二个参数是一个匿名方法

app.$on('reduce',function(){
    console.log('执行了reduce()');
    this.count--;
});

2、$once(执行一次的事件)

app.$once('reduceOnce',function(){
    console.log('只执行一次的方法');
    this.count--;
});

3、$off(关闭事件)

function off(){
    console.log('关闭事件');
    app.$off('reduce');
}

4、$emit(事件调用)

function reduce() {
    // 事件调用
    console.log('emit事件调用');
    app.$emit('reduce');
}

自定义指令

vue 中的自定义指令通过 Vue.directive 来实现,主要完成内置指令不能完成的一些事情。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之自定义指令</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
    <div v-test="color">
        {{num}}
    </div>
</div>
<button onclick="unbindApp()">解绑</button>

<script type="text/javascript">
// 解绑
function unbindApp() {
    app.$destroy();
}

// 自定义指令
Vue.directive("test",{
    //1-被绑定
    bind:function (el, binding, vnode) {
        console.log("1-bind 被绑定");
        console.log("el:",el);
        console.log("binding:",binding);
        console.log("vnode:",vnode);
        el.style.color = binding.value;
    },
    //2-被插入
    inserted:function (el, binding, vnode) {
        console.log("2-inserted 被插入");
    },
    //3-更新
    update:function (el, binding, vnode) {
        console.log("3-update 更新");
    },
    //4-更新完成
    componentUpdated:function (el, binding, vnode) {
        console.log("4-componentUpdated 更新完成");
    },
    //5-解绑
    unbind:function (el, binding, vnode) {
        console.log("5-unbind 解绑");
    }
});

var app = new Vue({
    el:'#app',
    data:{
        num: 123,
        color:'red'
    }
})
</script>
</body>
</html>

1、调试步骤

(1)chrome打开控制器查看

(2)控制台输入“ app.num='通过控制台设置的新name'

(3)点击解绑按钮

2、参数说明

     el:指令所绑定的元素,可以用来直接操作 DOM
binding: 一个对象,包含指令的很多信息
 vnode::Vue编译生成的虚拟节点

3、生命周期

自定义指令有五个生命周期(也叫钩子函数),分别是 bind、inserted、update、componentUpdated、unbind,说明如下:

1、bind:

只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个绑定时执行一次的初始化动作。

2、inserted:

被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)

3、update:

被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。

通过比较更新前后的绑定值,可以忽略不必要的模板更新。

4、componentUpdated:被绑定元素所在模板完成一次更新周期时调用。

5、unbind:只调用一次,指令与元素解绑时调用

组件基础

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之组件</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>

<div id="app">
    <!-- 全局组件 -->
    <div><button-counter></button-counter></div>
    <!-- 局部组件 -->
    <div><button-inner></button-inner></div>
    <!-- 常规属性传值 -->
    <div><button-props here="hello" from-here="world"></button-props></div>
    <!-- v-bind传值 -->
    <div><button-props v-bind:here="message" :from-here="message"></button-props></div>
    <!-- 父子组件调用 -->
    <div><parent></parent></div>
</div>

<script type="text/javascript">
// 定义全局组件
Vue.component('button-counter', {
    data: function () {
        return {
            count: 0
        }
    },
    template: '<button v-on:click="count++">全局组件显示: {{ count }}</button>'
});

// 子组件
var city = {
    template:`<div>Sichuan of China</div>`
}
// 父组件
var parent = {
    template:
        `<div>
            <p> Panda from China!</p>
            <city></city>
        </div>`,
    components:{
        "city": city
    }
}

// 实例化
new Vue({
    el: '#app',
    data: {
        message: 'hello'
    },
    // 定义局部组件
    components:{
        "button-inner":{
            data: function() {
                return {
                    inner: 0
                }
            },
            template: '<button v-on:click="inner++">局部组件显示: {{ inner }}</button>'
        },
        // 取值
        "button-props":{
            template:`<div style="color:red;">参数1: {{ here }}:---参数2: {{fromHere}}</div>`,
            props:['here', 'fromHere']
        },
        // 组件注册
        "parent": parent
    }
});
</script>
</body>
</html>

1、组件注册 component

(1)全局注册

// script
Vue.component('button-counter', {
    data: function () {
        return {
            count: 0
        }
    },
    template: '<button v-on:click="count++">全局组件显示: {{ count }}</button>'
});

new Vue({
    el: '#app'
});

// html使用
<button-counter></button-counter>

(2)局部注册

// script
new Vue({
    el: '#app',
    components:{
        "button-inner":{
            data: function() {
                return {
                    inner: 0
                }
            },
            template: '<button v-on:click="inner++">局部组件显示: {{ inner }}</button>'
        }
    }
});

// html使用
<button-inner></button-inner>

2、props 属性传值

(1)属性取值

// script
new Vue({
        el: '#app',
        components:{
            "button-props":{
                template:`<div style="color:red;">参数1: {{ here }}:---参数2: {{fromHere}}</div>`,
                props:['here', 'fromHere']
            }
        }
    });

// html使用
<button-props here="hello" from-here="world"></button-props>

PS:如果属性带 “-”,props 中需要驼峰取值

(2)在构造器向组件传值(v-bind)

// script
new Vue({
        el: '#app',
        data: {
            message: 'hello'
        },
        components:{
            "button-props":{
                template:`<div style="color:red;">参数1: {{ here }}:---参数2: {{fromHere}}</div>`,
                props:['here', 'fromHere']
            }
        }
    });

// html使用
<button-props v-bind:here="message" :from-here="message"></button-props>

3、父子组件

// script
// 子组件
var city = {
    template:`<div>Sichuan of China</div>`
}
// 父组件
var parent = {
    template:
        `<div>
            <p> Panda from China!</p>
            <city></city>
        </div>`,
    components:{
        "city": city
    }
}

// 实例化
new Vue({
    el: '#app',
    // 定义局部组件
    components:{
        // 组件注册
        "parent": parent
    }
});

// html使用
<parent></parent>

制作模板

vue 中的模板使用 template 来实现。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue入门之组件</title>
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
    <!-- template标签模板 -->
    <template id="demo2">
        <h2 style="color:red">我是template标签模板</h2>
    </template>
</div>

<!-- script标签模板 -->
<script type="x-template" id="demo3">
    <h2 style="color:red">我是script标签模板</h2>
</script>

<script type="text/javascript">
    // 实例化
    new Vue({
        el: '#app',
        data: {
            message: 'hello'
        },
        // 选项模板
        //template:`<h1 style="color:red">我是选项模板</h1>`
        //template:'#demo2'
        template:'#demo3'
    });
</script>
</body>
</html>

1、选项模板

<div id="app">
</div>

<script type="text/javascript">
    // 实例化
    new Vue({
        el: '#app',
        data: {
            message: 'hello'
        },
        template:`<h1 style="color:red">我是选项模板</h1>`
    });
</script>

2、标签模板

<div id="app">
    <template id="demo2">
        <h2 style="color:red">我是template标签模板</h2>
    </template>
</div>

<script type="text/javascript">
    // 实例化
    new Vue({
        el: '#app',
        data: {
            message: 'hello'
        },
        template:'#demo2'
    });
</script>

3、<script> 标签模板

<div id="app">
</div>

<script type="x-template" id="demo3">
    <h2 style="color:red">我是script标签模板</h2>
</script>

<script type="text/javascript">
    // 实例化
    new Vue({
        el: '#app',
        data: {
            message: 'hello'
        },
        template:'#demo3'
    });
</script>

插槽 slot

插槽,也就是 slot,是组件的一块HTML模板,一个 slot 最核心的两个问题是显示不显示和怎样显示。

1、单个 slot

单个插槽,别名默认插槽、匿名插槽,不用设置 name 属性。

<div id="app">
    <children1>
        <span>12345</span>
    </children1>
</div>

<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        components: {
            children1: {
                template: "<button><slot></slot>单个插槽</button>"
            }
        }
    });
</script>

2、具名 slot

插槽加了 name 属性,就变成了具名插槽。

具名插槽可以在一个组件中出现 N 次,出现在不同的位置。

<div id="app">
    <children2>
        <span slot="first" @click="tobeknow">12345</span>
        <span slot="second">56789</span>
    </children2>
</div>

<script type="text/javascript">
var app = new Vue({
    el: '#app',
    methods: {
        tobeknow: function () {
            console.log("It is the parent's method");
        }
    },
    components: {
        children2: {//这个无返回值,不会继续派发  
            template: "<button><slot name='first'></slot>具名插槽,<slot name='second'></slot></button>"
        }
    }
});
</script>

3、作用域 slot

vue2.5 版本中 slot-scope 取代了 scope,来实现作用域插槽,主要用在组件调用中,具体在 template 标签上面使用 slot-scope 来获取插槽 slot 上面的属性值,获取值的为一个对象,slot-scope=”它可以取任意字符串”,在 element-ui 的组件中经常看到。

<div id="app">
    <!-- 将数据传递给组件 -->
    <tb-list :data="data">
        <!-- 获取slot上面的值 -->
        <template slot-scope="scope">
            <p>索引:{{JSON.stringify(scope)}}</p>
            <p>索引:{{scope.$index}}</p>
            <p>姓名:{{scope.row.name}}</p>
            <p>年龄: {{scope.row.age}}</p>
            <p>性别: {{scope.row.sex}}</p>
        </template>
    </tb-list>
</div>

<script type="text/javascript">
var app = new Vue({
    el: '#app',
    data: {
        data: [{
            name: 'kongzhi1',
            age: '29',
            sex: 'man'
        }]
    },
    components: {
        // 作用域slot
        'tb-list': {
            template:
                `<ul>
                    <li v-for="(item, index) in data">
                        <slot :row="item" :$index="index"></slot>
                    </li>
                </ul>`,
            // 获取值
            props: ['data']
        }
    }
});
</script>

Vue 项目中应用 vue-router

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

包含的功能有:

快速入门

vue-router 是 vue 官方的路由解决方案,简单易用,中文官方地址如下:vue-router 中文手册

安装

vue-router 是一个插件包,需要用 npm 来进行安装的。如果采用 vue-cli 构建初始化项目会提示安装,也可以自己使用命令安装:

npm install vue-router --save

解读核心文件

用 vue-cli 构建项目之后,在 src/router/index.js 文件中,看到以下的路由核心文件:

// 引入vue框架
import Vue from 'vue'
// 引入vue-router路由依赖
import Router from 'vue-router'
// 引入页面组件,命名为 HelloWorld
import HelloWorld from '@/components/HelloWorld'

// Vue全局使用Router
Vue.use(Router)

// 定义路由配置
export default new Router({
  routes: [                  //配置路由,这里是个数组
    {                        //每一个链接都是一个对象
      path: '/',             //链接路径
      name: 'HelloWorld',        //路由名称,
      component: HelloWorld      //对应的组件模板
    }
  ]
})

使用

在系统入口文件 main.js 中注入 router,代码如下:

// 引入vue框架
import Vue from 'vue'
// 引入根组件
import App from './App'
// 引入路由配置
import router from './router'

// 关闭生产模式下给出的提示
Vue.config.productionTip = false

// 定义实例
new Vue({
  el: '#app',
  router, // 注入框架中
  components: { App },
  template: '<App/>'
})

路由属性配置说明

代码如下:

export default new Router({
    mode: 'history', //路由模式,取值为history与hash
    base: '/', //打包路径,默认为/,可以修改
    routes: [
    {
        path: string, //路径
        ccomponent: Component; //页面组件
        name: string; // 命名路由-路由名称
        components: { [name: string]: Component }; // 命名视图组件
        redirect: string | Location | Function; // 重定向
        props: boolean | string | Function; // 路由组件传递参数
        alias: string | Array<string>; // 路由别名
        children: Array<RouteConfig>; // 嵌套子路由
        beforeEnter?: (to: Route, from: Route, next: Function) => void; // 路由单独钩子
        meta: any; // 自定义标签属性,比如:是否需要登录
        icon: any; // 图标
        // 2.6.0+
        caseSensitive: boolean; // 匹配规则是否大小写敏感?(默认值:false)
        pathToRegexpOptions: Object; // 编译正则的选项
    }
    ]
})

页面跳转

一、router-link 标签跳转

在 html 标签内使用 router-link 跳转,相应于超链接 a 标签,使用方式如下:

<router-link to="/">[显示字段]</router-link>

to:导航路径

使用示例如下:

<p>导航 :
   <router-link to="/">首页</router-link>
   <router-link to="/hello">hello</router-link>
</p>

二、编程式导航-JS代码内部跳转

实际项目中,很多时候都是通过在JS代码内部进行导航的跳转,使用方式如下:

this.$router.push('/xxx')

具体的简单用法:

(1)先编写一个按钮,在按钮上绑定 goHome( ) 方法。

<button @click="goHome">回到首页</button>

(2)在 <script> 模块里加入 goHome 方法,并用 this.$router.push(‘/’) 导航到首页

export default {
    name: 'app',
    methods: {
        goHome(){
            this.$router.push('/home');
        }
    }
}

三、其他常用方法

//  后退一步记录,等同于 history.back()
this.$router.go(-1)
// 在浏览器记录中前进一步,等同于 history.forward()
this.$router.go(1)

子路由-路由嵌套

子路由,也叫路由嵌套,采用在 children 后跟路由数组来实现,数组里和其他配置路由基本相同,需要配置 pathcomponent,然后在相应部分添加 <router-view/> 来展现子页面信息,相当于嵌入 iframe

1、src/components/Home.vue(父页面)

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <!-- 添加子路由导航 -->
        <p>导航 :
            <router-link to="/home">首页</router-link> | 
            <router-link to="/home/one">-子页面1</router-link> |
            <router-link to="/home/two">-子页面2</router-link>
        </p>
        <!-- 子页面展示部分 -->
        <router-view/>
    </div>
</template>

<script>
export default {
    name: 'Home',
    data () {
        return {
            msg: 'Home Page!'
        }
    }
}
</script>

<style scoped>
</style>

2、src/components/One.vue(子页面1)

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
    </div>
</template>
<script>
export default {
    name: 'One',
    data () {
        return {
            msg: 'Hi, I am One Page!'
        }
    }
}
</script>

<style scoped>
</style>

3、src/components/Two.vue(子页面2)

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
    </div>
</template>
<script>
export default {
    name: 'Two',
    data () {
        return {
            msg: 'Hi, I am Two Page!'
        }
    }
}
</script>

<style scoped>
</style>

4、src/router/index.js(路由配置)

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import One from '@/components/One' 
import Two from '@/components/Two'

Vue.use(Router)

export default new Router({
    routes: [
    {
        path: '/', // 默认页面重定向到主页
        redirect: '/home'
    },
    {
        path: '/home', // 主页路由
        name: 'Home',
        component: Home,
        children:[ // 嵌套子路由
            {
                path:'one', // 子页面1
                component:One
            },
            {
                path:'two', // 子页面2
                component:Two
            },
        ]
    }
    ]
})

路由传递参数

1、通过 <router-link> 标签中的 to 传参

基本语法:

<router-link :to="{name:xxx, params: {key:value}}">
valueString
</router-link>

PS:上面 to 前边是带冒号,后边跟的是一个对象形势的字符串

  name:在路由配置文件中起的 name 值。叫做命名路由,下一节会讲到。
params:要传的参数,它是对象形式,在对象里可以传递多个值。

具体实例如下:

(1)在 src/components/Home.vue 里面导航中添加如下代码:

<router-link :to="{name: 'one', params:{username:'test123'}}">
子页面1
</router-link>

(2)在 src/router/indes.js 中添加如下代码,重点是 name:

{
    path:'one', // 子页面1
    name: 'one', // 路由名称-命名路由
    component:One
}

(3)在 src/components/One.vue 里面接受参数,代码如下:

<h2>{{$route.params.username}}</h2>

2、url 中传递参数

(1)在路由中以冒号传递,在 src/router/index.js 中加入如下代码:

{
    path:'/home/two/:id/:name', // 子页面2
    component:Two
},

(2)接受参数,在 src/components/Two.vue 中加入如下代码:

<p>ID:{{ $route.params.id}}</p>
<p>名称:{{ $route.params.name}}</p>

(3)路由跳转,在 src/components/Home.vue 中加入如下代码:

<router-link to="/home/two/1/张三">子页面2</router-link>

PS:to 前没有冒号为字符串路由,必须全部匹配。

(4)如果路由参数需要有特定的规则,就需要加入正则表达式了,示例如下:

{
    path:'/home/two/:id(\\d+)/:name', // 子页面2
    component:Two
}

源码 E:\node\vue296\src\router\index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import One from '@/components/One'
import Two from '@/components/Two'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/', // 默认页面重定向到主页
            redirect: '/home'
        },
        {
            path: '/home', // 主页路由
            name: 'Home',
            component: Home,
            children: [ // 嵌套子路由
                {
                    path: 'one', // 子页面1
                    name: 'one', // 路由名称-命名路由
                    component: One
                },
                {
                    path: '/home/two/:id/:name', // 子页面2
                    component: Two
                },
            ]
        }
    ]
})

E:\node\vue296\src\components\Two.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <p>ID:{{ $route.params.id}}</p>
        <p>名称:{{ $route.params.name}}</p>
    </div>
</template>
<script>
export default {
    name: 'Two',
    data () {
        return {
            msg: 'Hi, I am Two Page!'
        }
    }
}
</script>

<style scoped>
</style>

E:\node\vue296\src\components\Home.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <!-- 添加子路由导航 -->
        <p>导航 :
            <router-link to="/home">首页</router-link> | 
            <router-link to="/home/one">-子页面1</router-link> |
            <router-link to="/home/two">-子页面2</router-link>
            <br>
            <router-link :to="{name: 'one', params:{username:'test123'}}">子页面1传递参数</router-link>
            <br>
            <router-link to="/home/two/1/张三">子页面2</router-link>
        </p>
        <!-- 子页面展示部分 -->
        <router-view/>
    </div>
</template>

<script>
export default {
    name: 'Home',
    data () {
        return {
            msg: 'Home Page!'
        }
    }
}
</script>

<style scoped>
</style>

编程式导航 -params 传递参数

(1)在 src/router/index.js 页面加入如下代码:

{
    path:'/home/three', // 子页面3
    name: 'three',
    component:Three
}

(2)在 src/components/Three.vue 页面加入如下代码:

<p>ID:{{ $route.params.id}}</p>
<p>名称:{{ $route.params.name}}</p>

(3)在 src/components/Home.vue 中加入如下代码:

// template
<button @click="toThreePage">页面3-params传参</button>

// script
methods: {
    toThreePage() {
        this.$router.push({name: 'three', params: {id: 1, name: 'zhangsan'}})
    }
}

说明:

A、动态路由使用 params 传递参数,在 this.$router.push() 方法中 path 不能和 params 一起使用,否则 params 将无效。需要用 name 来指定页面。

B、以上方式参数不会显示到浏览器的地址栏中,如果刷新一次页面,就获取不到参数了,改进方式将第一部中的代码改成如下:

{
    path:'/home/three/:id/:name', // 子页面3
    name: 'three',
    component:Three
}

源码 E:\node\vue296\src\router\index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/', // 默认页面重定向到主页
            redirect: '/home'
        },
        {
            path: '/home', // 主页路由
            name: 'Home',
            component: Home,
            children: [ // 嵌套子路由
                {
                    path: 'one', // 子页面1
                    name: 'one', // 路由名称-命名路由
                    component: One
                },
                {
                    path: '/home/two/:id/:name', // 子页面2
                    component: Two
                },
                {
                    path:'/home/three/:id/:name', // 子页面3
                    name: 'three',
                    component:Three
                }
            ]
        }
    ]
})

E:\node\vue296\src\components\Three.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <p>ID:{{ $route.params.id}}</p>
        <p>名称:{{ $route.params.name}}</p>
    </div>
</template>
<script>
export default {
    name: 'Three',
    data () {
        return {
            msg: 'Hi, I am Three Page!'
        }
    }
}
</script>

<style scoped>
</style>

E:\node\vue296\src\components\Home.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <!-- 添加子路由导航 -->
        <p>导航 :
            <router-link to="/home">首页</router-link> | 
            <router-link to="/home/one">-子页面1</router-link> |
            <router-link to="/home/two">-子页面2</router-link>
            <br>
            <router-link :to="{name: 'one', params:{username:'test123'}}">子页面1传递参数</router-link>
            <br>
            <router-link to="/home/two/1/张三">子页面2</router-link>
            <br>
            <button @click="toThreePage">页面3-params传参</button>
        </p>
        <!-- 子页面展示部分 -->
        <router-view/>
    </div>
</template>

<script>
export default {
    name: 'Home',
    data () {
        return {
            msg: 'Home Page!'
        }
    },
    methods: {
        toThreePage() {
            this.$router.push({name: 'three', params: {id: 1, name: 'zhangsan'}})
        }
    }
}
</script>

<style scoped>
</style>

编程式导航 -query 传递参数

(1)在 src/router/index.js 页面加入如下代码:

{
    path:'/home/three', // 子页面3
    name: 'three',
    component:Three
}

(2)在 src/components/Three.vue 页面加入如下代码:

<p>ID:{{ $route.query.id}}</p>
<p>名称:{{ $route.query.name}}</p>

(3)在 src/components/Home.vue 中加入如下代码:

// template
<button @click="toThreePage">页面3-params传参</button>

// script
methods: {
    toThreePage() {
        this.$router.push({path: '/home/three', query: {id: 1, name: 'zhangsan'}})
    }
}

PS:动态路由使用 query 传递参数,会显示到浏览器地址栏中,

以上链接为 /home/three?id=1&name=zhangsan

源码

E:\node\vue296\src\router\index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/', // 默认页面重定向到主页
            redirect: '/home'
        },
        {
            path: '/home', // 主页路由
            name: 'Home',
            component: Home,
            children: [ // 嵌套子路由
                {
                    path: 'one', // 子页面1
                    name: 'one', // 路由名称-命名路由
                    component: One
                },
                {
                    path: '/home/two/:id/:name', // 子页面2
                    component: Two
                },
                {
                    path:'/home/three', // 子页面3
                    name: 'three',
                    component:Three
                }
            ]
        }
    ]
})

E:\node\vue296\src\components\Three.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <p>ID:{{ $route.query.id}}</p>
        <p>名称:{{ $route.query.name}}</p>
    </div>
</template>
<script>
export default {
    name: 'Three',
    data () {
        return {
            msg: 'Hi, I am Three Page!'
        }
    }
}
</script>

<style scoped>
</style>

E:\node\vue296\src\components\Home.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <!-- 添加子路由导航 -->
        <p>导航 :
            <router-link to="/home">首页</router-link> | 
            <router-link to="/home/one">-子页面1</router-link> |
            <router-link to="/home/two">-子页面2</router-link>
            <br>
            <router-link :to="{name: 'one', params:{username:'test123'}}">子页面1传递参数</router-link>
            <br>
            <router-link to="/home/two/1/张三">子页面2</router-link>
            <br>
            <button @click="toThreePage">页面3-params传参</button>
        </p>
        <!-- 子页面展示部分 -->
        <router-view/>
    </div>
</template>

<script>
export default {
    name: 'Home',
    data () {
        return {
            msg: 'Home Page!'
        }
    },
    methods: {
        toThreePage() {
            this.$router.push({path: '/home/three', query: {id: 1, name: 'zhangsan'}})
        }
    }
}
</script>

<style scoped>
</style>

命名路由-命名视图-重定向-别名

1、命名路由

给一个路由命一个唯一的名称,然后跳转调用这个名称即可。

(1)在 src/router/index.js 中加一个带 name 的路由,代码如下:

{
    path: 'one', // 子页面1
    name: 'one', // 路由名称-命名路由
    component: One // 页面组件
}

(2)在 src/component/Home.vue 页面中调用,代码如下:

// template跳转调用
<router-link :to="{name: 'one'}">子页面1</router-link>

// router.push函数跳转调用
router.push({ name: 'user'}})

2、命名视图

在同一个页面展示多个视图,如果不用嵌套,只能采用命名视图来实现了。

代码如下:

(1)在 src/router/index.js 中,代码如下:

import Vue from 'vue'
import Router from 'vue-router'
// 创建页面组件
const Header = { template: '<div>Header</div>' }
const Left = { template: '<div>Left</div>' }
const Right = { template: '<div>Right</div>' }

Vue.use(Router)

export default new Router({
    routes: [
	    {
	        path: '/', // 主页路由
	        components: {
	            default: Header,
	            a: Left,
	            b: Right
	        }
	    }
    ]
})

(2)在 src/App.vue 中,代码如下:

<template>
    <div id="app">
        <router-view />
        <router-view name="a" class="left" />
        <router-view name="b" class="right" />
    </div>
</template>

<script>
export default {
    name: 'App'
}
</script>

<style>
#app {
    text-align: center;
    color: #2c3e50;
    width: 500px;
    border: 1px solid red;
    margin: 0 auto;
}

.left,.right{
    float: left;
    width:48%;
    text-align: center;
    border:1px solid red
}
</style>

PS:经过实践,命名视图只能放在最顶级的页面中,即第一步中的代码不能放在其他页面中。

3、重定向

重定向是通过 route 的配置中关键词 redirect 来实现的,具体代码如下:

(1)在 src/router/index.js 中,代码如下:

export default new Router({
    routes: [
	    {
	        path: '/', // 默认页面重定向到主页
	        redirect: '/home' // 重定向
	    },
	    {
	        path: '/home', // 主页路由
	        component: Home,
	        children:[ // 嵌套子路由
	            {
	                path:'/home/two/:id/:name', // 子页面2
	                component:Two
	            },
	            {
	                path:'/home/three/:id/:name', // 子页面3
	                name: 'three', // 路由名称-命名路由
	                redirect: '/home/two/:id/:name' // 重定向-传递参数
	            },
	        ]
	    }
    ]
})

(2)在 src/components/Home.vue 中,代码如下:

<router-link to="/">首页</router-link> | 
<router-link to="/home/two/1/lisi">子页面2</router-link>  |
<router-link :to="{name: 'three', params: {id: 1, name: 'zhangsan'}}">
子页面3
</router-link>

说明1-不带参数的重定向:

redirect: '/home' // 重定向-不带参数

说明2-带参数的重定向:

redirect: '/home/two/:id/:name' // 重定向-传递参数

4、别名

重定向是通过 route 的配置中关键词 alias 来实现的,具体代码如下:

(1)在 src/router/index.js 中,代码如下:

{
    path:'/one', // 子页面1
    component:One,
    alias: '/oneother'
}

(2)在 src/components/Home.vue 中,代码如下:

<router-link to="/oneother">子页面1</router-link>

说明1:redirect 和 alias 的区别

redirect:直接改变了 url 的值,把 ur l变成了真实的 path 路径。\

alias:

url 路径没有别改变,这种更友好,让用户知道自己访问的路径,只是改变了 <router-view> 中的内容。

说明2:别名请不要用在 path 为 ’/’ 中,如下代码的别名是不起作用的。

<router-link to="/oneother">子页面1</router-link>

过渡动画

(1)在 <router-view> 标签的外部添加 <transition> 标签,标签还需要一个 name 属性,代码如下:

<transition name="fade" mode="out-in">
    <router-view />
</transition>

过渡模式 mode

in-out:新元素先进入过渡,完成之后当前元素过渡离开,默认模式。

out-in:当前元素先进行过渡离开,离开完成后新元素过渡进入。

(2)加入CSS,一共4个CSS类名,四个类名与 transitionname 属性有关,比如name=”fade”,相应的 css 如下:

/*页面切换动画*/
/*进入过渡的结束状态,元素被插入时就生效,在过渡过程完成后移除*/
.fade-enter-active {
    transition: opacity .5s;
}
/*进入过渡的开始状态,元素被插入时生效,只应用一帧后立刻删除*/
.fade-enter {
    opacity: 0;
}
/*离开过渡的开始状态,元素被删除时触发,只应用一帧后立刻删除*/
.fade-leave {
    opacity: 1;
}
/*离开过渡的结束状态,元素被删除时生效,离开过渡完成后被删除*/
.fade-leave-active {
    opacity:0;
    transition: opacity .5s;
}

文件:E:\node\vue296\src\App.vue

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <transition name="fade" mode="out-in">
        <router-view />
    </transition>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
/*页面切换动画*/
/*进入过渡的结束状态,元素被插入时就生效,在过渡过程完成后移除*/
.fade-enter-active {
    transition: opacity .5s;
}
/*进入过渡的开始状态,元素被插入时生效,只应用一帧后立刻删除*/
.fade-enter {
    opacity: 0;
}
/*离开过渡的开始状态,元素被删除时触发,只应用一帧后立刻删除*/
.fade-leave {
    opacity: 1;
}
/*离开过渡的结束状态,元素被删除时生效,离开过渡完成后被删除*/
.fade-leave-active {
    opacity:0;
    transition: opacity .5s;
}
</style>

mode 与 404

1、mode 模式

代码示例:

export default new Router({
    mode: 'history', //mode模式
    routes: [...]
})

mode取值说明:

(1)histroy:URL就像正常的 url,示例:http://localhost:8080/home
(2)   hash:默认值,会多一个 “#”,示例:http://localhost:8080/#/home

2、404页面设置

如果访问的路由不存在,或者用户输入错误时,会有一个404友好的提示页面,配置如下:

(1)在 /src/router/index.js 中加入如下代码:

// 404
{
    path: '*',
    component: () => import('@/components/404')
}

(2)在 src/components/404.vue 中编写如下代码:

<template>
    <div class="hello">
        <h1>404 not found</h1>
    </div>
</template>
<script>
export default {
    data () {
        return {

        }
    }
}
</script>

<style scoped>
</style>

路由钩子

路由钩子,即导航钩子,其实就是路由拦截器,vue-router 一共有三类:

1、全局钩子:最常用

2、路由单独钩子

3、组件内钩子

1、全局钩子

src/router/index.js 中使用,代码如下:

// 定义路由配置
const router = new VueRouter({ ... })

// 全局路由拦截-进入页面前执行
router.beforeEach((to, from, next) => {
    // 这里可以加入全局登陆判断
    // 继续执行
    next();
});

// 全局后置钩子-常用于结束动画等
router.afterEach(() => {
    //不接受next
});

export default router;

每个钩子方法接收三个参数:

     to: Route : 即将要进入的目标 [路由对象]
   from: Route : 当前导航正要离开的路由
next: Function : 继续执行函数

                          next():继续执行
                     next(false):中断当前的导航。
next(‘/‘) 或 next({ path: ‘/‘ }):跳转新页面,常用于登陆失效跳转登陆

2、路由单独钩子

使用:在路由配置中单独加入钩子,在 src/router/index.js 中使用,代码如下:

{
          path:'/home/one', // 子页面1
     component: One,
   // 路由内钩子
   beforeEnter: (to, from, next) => {
   console.log('进入前执行');
       next();
   }
}

3、组件内钩子

使用:在路由组件内定义钩子函数:

beforeRouteEnter:进入页面前调用
beforeRouteUpdate (2.2 新增):页面路由改变时调用,一般需要带参数
beforeRouteLeave:离开页面调用

任意找一页面,编写如下代码:

<script>
export default {
    name: 'Two',
    data () {
        return {
            msg: 'Hi, I am Two Page!'
        }
    },
    // 进入页面前调用
    beforeRouteEnter(to, from, next) {
        console.log('进入enter路由钩子')
        next()
    },
    // 离开页面调用
    beforeRouteLeave(to,from, next){
        console.log('进入leave路由钩子')
        next()
    },
    // 页面路由改变时调用
    beforeRouteUpdate(to, from, next) {
        console.log('进入update路由钩子')
        console.log(to.params.id)
        next()
    }
}
</script>

路由懒加载

1、路由正常模式:

// 1、先引入页面组件
import Home from '@/components/Home'

// 2、使用组件
{
   path: '/home',
   component: Home
}

2、懒加载模式

大项目中,为了提高初始化页面的效率,路由一般使用懒加载模式,一共三种实现方式。

(1)第一种写法:

component: (resolve) => require(['@/components/One'], resolve)

(2)第二种写法:

component: () => import('@/components/Two')

(3)第三种写法:

components: r => require.ensure([], () => r(require('@/components/Three')), 'group-home')

PS:

一般常用第二种简写
第三种中,’group-home’ 是把组件按组分块打包, 可以将多个组件放入这个组中,在打包的时候 Webpack 会将相同 chunk 下的所有异步模块打包到一个异步块里面。

路由懒加载用法:E:\node\vue296\src\router\index.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import One from '@/components/One'
import Two from '@/components/Two'
import Three from '@/components/Three'

Vue.use(Router)

export default new Router({
    mode: 'history', //mode模式
    routes: [
        {
            path: '/', // 默认页面重定向到主页
            redirect: '/home'
        },
        {
            path: '/home', // 主页路由
            name: 'Home',
            component: Home,
            children: [ // 嵌套子路由
                {
                    path: 'one', // 子页面1
                    name: 'one', // 路由名称-命名路由
                    component: One
                },
                {
                    path: '/home/two/:id/:name', // 子页面2
                    component: Two
                },
                {
                    path:'/home/three', // 子页面3
                    name: 'three',
                    component:Three
                }
            ]
        },
        {
            path: '*',
            component: () => import('@/components/404')
        }
    ]
})

vuex 背景引言

1、vuex是什么?

vuex是一个专为 Vue.js 应用程序开发的 状态管理模式

它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

chrome 安装调试工具 devtools extension

2、单向数据流

示意图说明:

  State:驱动应用的数据源(单向数据流)
   View:以声明方式将 state 映射到视图(静态显示出来的数据源)
Actions:处理用户在 view 上面操作而导致的状态变化(数据源变化追踪)

一个简单的 demo 案例:
E:\node\vue296\src\router\index.js

// 引入组件
import HelloWorld from '@/components/HelloWorld'

// 添加路由
{
    path: '/hello',
    name: 'HelloWorld',
    component: HelloWorld,
}

E:\node\vue296\src\components\Home.vue 首页

<!-- 添加跳转 -->
<router-link to="/hello">Hello页</router-link>

E:\node\vue296\src\components\HelloWorld.vue 案例页

<template>
    <div>
        <!-- view -->
        <div>{{ count }}</div>
        <button @click="increment">increment</button>
    </div>
</template>
<script>
export default {
    // state
    data () {
        return {
            count: 0
        }
    },
    // actions
    methods: {
        increment () {
            this.count++
        }
    }
}
</script>
<style scoped>

</style>

3、vuex 解决的问题

多个视图组件,包括父子组件,兄弟组件之间的状态共享。

不同视图组件的行为需要变更同一个状态。

4、vuex 使用场景

中大型单页应用,需要考虑如何更好地在组件外部管理状态,简单应用不建议使用。

5、vuex 与全局变量的区别

响应式:

vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会得到高效更新。

不能直接改变store:

不能直接改变 store 的变化,改变 store 中状态的唯一途径是 commit mutation,方便于跟踪每一个状态的变化。

6、vuex 核心流程

示意图说明:

1、Vue Components Vue组件:

HTML页面上,负责接收用户操作等交互行为,执行 dispatch 方法触发对应 action 进行回应。

2、Dispatch:操作行为触发方法,是唯一能执行 action 的方法。

3、Actions 操作行为处理模块:

负责处理 Vue Components 接收到的所有交互行为。

包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。

向后台API请求的操作就在这个模块中进行,包括触发其他 action 以及提交 mutation 的操作。该模块提供了 Promise 的封装,以支持 action 的链式触发。

4、Commit 态改变提交操作方法:

状对 mutation 进行提交,是唯一能执行 mutation 的方法。

5、Mutations 状态改变操作方法:

是 Vuex 修改 state 的唯一推荐方法,其他修改方式在严格模式下将会报错。

该方法只能进行同步操作,且方法名只能全局唯一。

操作之中会有一些 hook 暴露出来,以进行 state 的监控等。

6、State 页面状态管理容器对象:

集中存储 Vue components 中 data 对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。

7、Getters:state对象读取方法。

图中没有单独列出该模块,应该被包含在了render 中,Vue Components 通过该方法读取全局 state 对象。

总结说明:

Vue 组件接收交互行为,调用 dispatch 方法触发 action 相关处理,若页面状态需要改变,则调用 commit 方法提交 mutation 修改 state,通过 getters 获取到 state 新值,重新渲染Vue Components,界面随之更新。

入门示例

安装

PS E:\node\vue296> npm install --save vuex@3.6.2
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\watchpack-chokidar2\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules\webpack-dev-server\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ vuex@3.6.2
removed 1 package and updated 1 package in 8.474s
PS E:\node\vue296>

(1)新建 src/vuex/store.js 中写入以下代码:

// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'

// 使用vuex
Vue.use(Vuex)

// 1、state:创建初始化状态
const state = {
    // 放置初始状态
    count: 1
}

// 2、mutations:创建改变状态的方法
const mutations = {
    // 状态变更函数-一般大写
    ADD (state, n) {
        state.count += n;
    }
}

// 3、getters:提供外部获取state
const getters = {
    count: function(state){
        return state.count;
    }
}

// 4、actions:创建驱动方法改变mutations
const actions ={
    // 触发mutations中相应的方法-一般小写
    add ({commit}, data) {
        commit('ADD', data)
    }
}

// 5、全部注入Store中
const store = new Vuex.Store({
    state,
    mutations,
    getters,
    actions
});

// 6、输出store
export default store;

代码说明:

state - mutations - getters - actions - store,以上写法基本固定。

小型项目用上面的简单管理状态即可。

(2)src/main.js 代码中添加

import Vue from 'vue'
import App from './App'
import router from './router'
// 引入store
import store from './vuex/store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store, // 全局注入
  components: { App },
  template: '<App/>'
})

(3)src/compontent/Count.vue 页面组件中代码如下:

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>{{count}}</h2>
        <button @click="clickAdd">新增</button>
    </div>
</template>
<script>
export default {
    data () {
        return {
            msg: 'Vuex test!'
        }
    },
    computed: {
        // 获取 state 值
        count() {
            return this.$store.state.count;
        }
    },
    methods: {
        clickAdd() {
            //分发action中的add方法
            this.$store.dispatch('add', 1);
        }
    }
}
</script>
<style scoped>

</style>

state-状态对象的获取方法

1、在组件的 template 中直接使用

<h2>{{ $store.state.count }}</h2>

2、在计算属性 computed 中直接赋值

// 方式1:直接获取
computed: {
    count() {
        // this指的是main.js中的vue实例对象
        return this.$store.state.count;
    }
}

3、通过 mapState 的对象来赋值

// 方式2:利用mapState
computed: mapState({
    // es5写法
    count: function (state) {
         return state.count;
     },
    // es6写法
    count: state => state.count
})

4、通过 mapState 的数组来赋值

// 方式3:数组获取
computed: mapState(['count'])

5、通过 mapState 的 JSON 来赋值

// 方式4:JSON获取
computed: mapState({
    count: 'count'
})

PS:一般 4 和 5 两种比较常用

完整示例代码:E:\node\vue296\src\components\Count.vue

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>{{ $store.state.count }}</h2>
        <h2>{{count}}</h2>
        <button @click="clickAdd">新增</button>
    </div>
</template>
<script>
import {mapState} from 'vuex'
export default {
    data () {
        return {
            msg: 'Vuex test!'
        }
    },
    // 方式1:在计算属性computed中直接赋值
    // computed: {
    //     count() {
    //         // this指的是main.js中的vue实例对象
    //         return this.$store.state.count;
    //     }
    // },
    // 方式2:通过mapState的对象来赋值
    // computed: mapState({
    //     // es5
    //     // count: function (state) {
    //     //     return state.count;
    //     // },
    //     // es6
    //     count: state => state.count
    // }),
    // 方式3:通过mapState的对象来赋值
    // computed: mapState(['count']),
    // 方式4:通过mapState的JSON来赋值
    computed: mapState({
        count: 'count'
    }),
    methods: {
        clickAdd() {
            //分发action中的add方法
            this.$store.dispatch('add', 1);
        }
    }
}
</script>
<style scoped>

</style>

mutations - getters - actions 异步 1、mutations(修改状态)

(1)template 中直接使用 $store.commit( ) 触发

// template
<button @click="$store.commit('ADD')">+</button>

// src/vuex/store.js
const mutations = {
    // 状态变更函数
    ADD (state) {
        state.count++;
    }
}

(2)利用 mapMutations 引入触发

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>{{count}}</h2>
        <!-- 3、、直接调用相应的方法 -->
        <button @click="ADD">+</button>
    </div>
</template>

<script>
// 1、引入mapMutations
import {mapState, mapMutations} from 'vuex'
export default {
    data () {
        return {
            msg: 'Vuex test!'
        }
    },
    // 通过mapState的JSON来赋值
    computed: mapState({
        count: 'count'
    }),
    // 2、methods中加入mapMutations
    methods: mapMutations([
        'ADD'
    ])
}
</script>
<style scoped>

</style>

2、getters(获取state和过滤)

(1)基本用法

// src/vuex/store.js
const getters = {
    count: function(state){
        // 返回加上100
        return state.count + 100;
    }
}

(2)常规获取值

computed: {
    // 获取getters
    count(){
        return this.$store.getters.count;
    }
}

(3)mapGetters 获取值

// 1、引入mapMutations
import {mapState, mapMutations, mapGetters} from 'vuex'

// 2、使用
computed: {
    // 获取getters
    ...mapGetters(["count"])
}

3、actions(异步状态修改)

actions 和 mutations 功能基本一样,不同点是,actions 是异步的改变 state 状态,而mutations 是同步改变状态。

不过实际项目中一般都是通过 actions 改变 mutations 中的值。

(1)store.js 中增加异步代码

// src/vuex/store.js
const actions ={
    // 触发mutations中相应的方法
    add ({commit}) {
        // 增加异步
        setTimeout(()=>{
            commit('ADD')
        },3000);
        console.log('我比reduce提前执行');
    }
}

(2)常规使用

// template
<button @click="add">+</button>

// script
methods: {
    add() {
        //分发action
        this.$store.dispatch('add');
    }
}

(3)mapActions 的使用

// template
<button @click="add">+</button>

// script
// 引入mapActions
import {mapState, mapActions} from 'vuex'

// 使用mapActions
methods: {
    ...mapActions(['add'])
}

传递参数

在 vuex 的方法调用传递参数,只需要在 mutations 和 actions 相应的地方加上参数,然后调用的时候传入即可。

(1)src/vuex/store.js

// actions中传递参数
const mutations = {
    ADD (state, n) {
        state.count += n;
    }
}

// actions中传递参数
const actions ={
    // 触发mutations中相应的方法
    add ({commit}, n) {
        // 增加异步
        setTimeout(()=>{
            commit('ADD', n);
        },3000);
        console.log('我比reduce提前执行');
    }
}

(2)页面组件常规调用传递

// template
<button @click="add">+</button>

// script
methods: {
    add() {
        // 分发action
        this.$store.dispatch('add', 99);
     }
}

(3)页面组件使用 mapActions 调用传递

// template
<button @click="add(99)">+</button>

// script
methods: {
    ...mapActions(['add'])
}

module-模块组

当应用非常复杂,状态非常多的时候,需要将 store 分割成模块(module)。

每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块,从上至下进行同样方式的分割。

1、大致的结构

// 模块A
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

// 模块B
const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

// 组装
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

// 取值
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

2、详细示例

实际开发中建议把 module 分开编写。

(1)src/vuex/module1.js

// 模块1
const module1 = {
    // 初始化状态
    state: {
        module1: {
            name: '模块1'
        }
    },
    // 编写动作
    mutations: {
        CHANGE1 (state, data) {
            state.module1 = data;
        }
    },
    // 取值
    getters: {
        module1: function(state){
            return state.module1;
        }
    },
    // 创建驱动,可异步
    actions: {
        change1 ({commit}, data) {
            commit('CHANGE1', data)
        }
    }
}

export default module1;

(2)src/vuex/module2.js

// 模块2
const module2 = {
    // 初始化状态
    state: {
        module2: {
            name: '模块2'
        }
    },
    // 编写动作
    mutations: {
        CHANGE2 (state, data) {
            state.module2 = data;
        }
    },
    // 取值
    getters: {
        module2: function(state){
            return state.module2;
        }
    },
    // 创建驱动,可异步
    actions: {
        change2 ({commit}, data) {
            commit('CHANGE2', data)
        }
    }
}

export default module2;

(3)src/vuex/store.js

// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 引入module1
import module1 from '@/vuex/module1'
// 引入module2
import module2 from '@/vuex/module2'

// 使用vuex
Vue.use(Vuex)

// 模块注入
const store = new Vuex.Store({
    modules: {
        a: module1,
        b: module2
    }
})

// 输出store
export default store;

(4)组件中使用,src/compontent/one.vue

<template>
    <div id="app">
        <!-- module1 -->
        <h2>{{ module1.name }}</h2>
        <button @click="change1({'name': 'change1'})">module1改变</button>

        <!-- module2 -->
        <h2>{{ module2.name }}</h2>
        <button @click="change2({'name': 'change2'})">module2改变</button>
    </div>
</template>

<script>
// 引入快捷方法
import {mapState, mapGetters, mapActions} from 'vuex'

export default {
    name: 'app',
    data () {
        return {
        }
    },
    computed:{
        // mapState取值
        // ...mapState({
        //     module1: state => state.a.module1.name,
        //     module2: state => state.b.module2.name
        // })

        // mapGetter取值
        ...mapGetters(['module1', 'module2'])
    },
    methods: {
        // mapAction取方法
        ...mapActions([
            'change1',
            'change2'
        ])
    }
}
</script>
<style>

</style>

PS:module 中命名要唯一,不然获取值和改变值的时候会冲突,目前亲测 mapGetters 只能获取对象。

总结

到此这篇关于Vue命令行工具Vue-CLI图文的文章就介绍到这了,更多相关Vue命令行工具Vue-CLI内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文