Vue 0基础学习路线(13)—— 图解深度详述Vue脚手架和vue-cli、单文件组成、本地服务搭建、自定义脚手架配置及详细案例(附详细案例代码解析过程及版本迭代过程)

1. 脚手架—vue-cli

之前我们所讲述内容,都围绕的script标签引入的。

vue的脚手架工具和React的脚手架工具一样,综合了很多东西,如打包、构建、单元测试等,它其实就是一个集成开发环境,提供了很多工具。

Vue 提供了一个脚手架工具,帮助我们快速搭建本地项目:vue-cli

vue-clivue 提供的一个用于自动化构建和开发项目的工具,也称为:脚手架,它是一系列工具的集合,它主要有:

  • 根据配置选项自动构建项目,并安装所需要的依赖
  • 启动一个本地开发服务器,通过这个服务器可以基于服务器环境访问本地项目,同时提供了跨域代理服务
  • 项目的自动编译、打包
  • 项目测试(单元测试、e2e测试)

https://cli.vuejs.org/zh/

1.1 安装

npm install -g @vue/cli
// OR
yarn global add @vue/cli

在这里插入图片描述

在这里插入图片描述

看是否安装成功,可以输出vue命令

在这里插入图片描述

有点类似create-react-app脚手架工具,但是它提供了更多地特性。

查看版本

vue --version
// OR
vue -V

帮助

vue --help
// OR
vue -h

1.2 创建项目

vue-cli 提供了两种使用方式

  • 命令行-cli
  • 图形界面(基于浏览器) - UI
// 命令行
vue create 项目名称
// UI
vue ui

运行命令以后,根据提示进行选择

1.2.1 命令行方式创建项目

vue create 项目名称

vue create app

进入一个交互式页面:

第一个提示使用上下键选择,想要的选项:

默认配置(安装babel、eslint

手动配置(手动选择特性)

在这里插入图片描述

选择第二个回车,然后选择可以用到的去安装

提示 空格 选择、a全选 、 i反选

在这里插入图片描述

PWA 渐进式web应用

Vuex 状态管理方案

CSS Pre-processors CSS预处理器

Linter / Formatter 代码格式化、代码标准(代码规范)

Unit Testing单元测试

E2E Testting端到端测试,模拟用户与浏览器的交互,但不是人点,而是通过代码打开浏览器,用代码模拟人操作

选择完后,回车安装:

在这里插入图片描述

In dedicated config files: 单独保存在各自的配置文件中 => 刚才选择安装文件最终形成一个配置文件,可单独存放

In package.json: 保存在package.json文件中 => 融入package.json

在这里插入图片描述

选第一个

提示,是否把配置存起来,以备下次直接使用。

在这里插入图片描述

n,开始安装

在这里插入图片描述

在这里插入图片描述

运行

项目创建成功以后,进入项目根目录,打开 package.json 文件,我们可以看到

{
    
    
  ...,
  "scripts": {
    
    
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
    ...
}

https://cli.vuejs.org/zh/guide/cli-service.html#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4

cd app

yarn serve

在这里插入图片描述

在这里插入图片描述

1.2.2 UI式交互 —基于浏览器图形界面方式创建项目

vue ui

vue ui

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

安装完成后

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.2.3 扩展—什么是渐进式web应用?

PWA应用是指那些使用指定技术和标准模式来开发的web应用,这将同时赋予它们web应用原生应用的特性。

例如,web应用更加易于发现——相比于安装应用,访问一个网站显然更加容易和迅速,并且你可以通过一个链接来分享web应用

在另一方面,原生应用与操作系统可以更加完美的整合,也因此为用户提供了无缝的用户体验。你可以通过安装应用使得它在离线的状态下也可以运行,并且相较于使用浏览器访问,用户也更喜欢通过点击主页上的图标来访问它们喜爱的应用。

PWA赋予了我们创建同时拥有以上两种优势的应用的能力。

这并不是一个新概念——这样的想法在过去已经在web平台上通过许多方法出现了多次。渐进式增强和响应式设计已经可以让我们构建对移动端友好的网站。在多年以前的Firefox OS的生态系统中离线运行和安装web应用已经成为了可能。

PWAs, 不但如此,更是提供了所有的甚至是更多的特性,来让web更加优秀。

1.3 打包

npm build

在这里插入图片描述

yarn build

在这里插入图片描述

最终丢到服务器的代码就是dist里的文件。

在这里插入图片描述

1.4 目录结构

- node_modules/      安装的第三方插件及依赖       
- public/            应用的index.html,打包后的文件最终的入口
- src/               开发过程中的目录
    - assets/        开发用到的资源(通过import引入),如图片
    - components/    组件
    - app.vue
    - main.js        应用入口
- ...  几乎都是配置文件等,不是重点

在这里插入图片描述

src

先来说一个最重要的目录 src ,这个就是存放的就是我们项目源码的目录,我们开发过程中大部分的时间就在这个目录中

  • main.js

项目的入口文件

  • App.vue

首先,这是 vue 提供的一种单文件组件的文件模式(后续会讲),一个 .vue 文件就是一个独立的组件,这里的 App.vue 是应用的根组件

  • components 目录

存放组件的目录

  • assets 目录

存放静态资源的目录,比如:图片,css 等。这里的文件与外层 public 目录存放的静态资源的最大区别是:assets 存放的资源是通过 import 等方式作为模块导入,最后打包处理的。而 public 中的资源并不通过模块方式导入,一般都是通过 scriptlinkimg 等方式从浏览器引入的资源,比如无法通过模块化处理的 js 文件(这样的需求情况并不多)

public

一些并非通过模块方式引入的资源文件存放的位置,一般都是通过 script 、link 、img 等方式从浏览器引入的资源,比如无法通过模块化处理的 js 文件(这样的需求情况并不多)

\test01\app\src\main.js

import Vue from 'vue'
import App from './App.vue'
 
Vue.config.productionTip = false   // Vue 在启动时的生产提示
 
// 构建根组件
new Vue({
    
    
  // 没有采用template,而是render  
  render: h => h(App), // 对jsx进行渲染,h就是似虚拟dom的构建函数,类似react的dom底下的create方法,然后把组件传进去,进行渲染
}).$mount('#app')  // 挂载到页面id的app上

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.56
Branch: branch04

commit description:a1.56(vue脚手架工具构建项目)

tag:a1.56

vue为了方便进行组件开发,特意弄了.vue的文件,它帮助我们更为方便地进行组件开发,不过该文件不能直接被浏览器解析。实际上在webpack中加了vue-loader,最终被webpack解析成一个js文件,它返回回去的是一个对象(templete、样式等均组织到一个对象里与它进行融合)。

实际返回回去就是一个组件对象。

在这里插入图片描述

\app\src\App.vue

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
 
<script>
import HelloWorld from './components/HelloWorld.vue'
 
export default {
     
     
  name: 'App',
  components: {
     
     
    HelloWorld
  }
}
</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;
}
</style>
 

在这里插入图片描述

2. 单文件组件

vue 的单文件组件是官方提供的一种用来组织组件代码的形式,该文件以 .vue 为后缀,该文件会被 vue-cli 内置的 webpack 解析生成对应的 javascripthtmlcss 文件

https://vue-loader-v14.vuejs.org/zh-cn/start/spec.html

vue 也是基于组件的开发模式,我们知道一个 UI 组件包含

  • 结构
  • 样式
  • 行为

为了能够更加方便的编写组件,vue 提供了一个特殊的组件定义文件:.vue 文件,我们也称为 单文件组件

2.1 组成

一个单文件组件的 结构、样式、行为 分别通过三个标签来进行定义和划分(方便对组件进行编写)

  • <html>
  • <script>
  • <style>

单文件组件把一个组件所包含的 结构样式行为 分别通过 templatestylescript 进行分离包含,然后统一组织在一个文件中

注意:一个单文件组件最少必须包含 template,可以不需要 scriptstyle

2.2 lang (language)属性

无论是 templatescript 还是 style,都可以通过 lang 属性来指定它们所使用的语言

template默认是html语言,我们这里设置成jade

script默认是js,这里改成用ts

<template lang="jade">
  div.example
        p {
    
    {
    
     msg }}
</template>
 
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
    
    
  data () {
    
    
    return {
    
    
      msg: 'Hello world'
    }
  }
})
</script>
 
<style lang="stylus">
.example
  color red
</style>

2.3 src 属性

如果一个组件的模板脚本内容太多了,导致文件太大,可以把templatestylescript 进行分离

可以通过 src 属性把文件分离到单独的文件中

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

这里的 src 同样遵循模块化的导入规则,./ 开头的表示相对路径,/ 开头表示 NPM 包中的资源

2.4 有作用域的 CSS

style 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。这类似于 Shadow DOM 中的样式封装

<style scoped>
.example {
     
     
  color: red;
}
</style>
 
<template>
  <div class="example">hi</div>
</template>

解析后:

<style>
.example[data-v-f3f3eg9] {
     
     
  color: red;
}
</style>
 
<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

2.4.1 example01

2.4.1.1 example01-1

\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
  </div>
</template>
 
<script>
export default {
     
     
  name: 'HelloWorld',
  props: {
     
     
    msg: String
  }
}
</script>
 
 
<style>
</style>

\app\src\App.vue

<template>
  <div id="app">
    <h1>软件开发</h1>
    <p>前端Vue</p>
    <hr>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
 
<script>
import HelloWorld from './components/HelloWorld.vue'
 
export default {
     
     
  name: 'App',
  components: {
     
     
    HelloWorld
  }
}
</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;
}
</style>

在这里插入图片描述

vue脚手架demo\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
  </div>
</template>
 
<script>
  export default {
     
     
    name: 'HelloWorld',
    props: {
     
     
      msg: String
    }
  }
</script>
 
 
<style>
p {
     
     
  color: red;
}
</style>

vue脚手架demo\app\src\App.vue

<template>
  <div id="app">
    <h1>软件开发</h1>
    <p>前端Vue</p>
    <hr>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
 
<script>
  import HelloWorld from './components/HelloWorld.vue'
 
  export default {
     
     
    name: 'App',
    components: {
     
     
      HelloWorld
    }
  }
</script>
 

在这里插入图片描述

我们发现这里会有一个问题 =>

编译后的html的样式,这个样式会影响全局。它把全部的p标签(组件里和组件外的p标签),但是封装组件的目的是使数据、模板是独立的,样式也应该使独立的。

但是CSS中没有默认作用域的问题,所以它采取了一个特别的手段,加载了一个第三方模块,主要用来处理CSS module的(模块问题)。

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.57
Branch: branch04

commit description:a1.57(example01-1——css无独立作用域的隐患)

tag:a1.57

2.4.1.2 example01-2

<style scoped>
  p{
     
     
    color: red;
  }
</style>

scoped它会使组件相关的模板,都加了data-v-469af010469af010是一个hash值,每一个组件都有自己独立的hash值。组件中所有标签都会加上该属性,并且在css中加一个选择器data-v-469af010,这样就只会处理该类组件的标签元素了。这样就解决css作用域的问题了。

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.58
Branch: branch04

commit description:a1.58(example01-2——用scoped解决css无独立作用域的隐患)

tag:a1.58

2.4.2 混用本地和全局样式

<style>
/* 全局样式 */
</style>
 
<style scoped>
/* 本地样式 */
</style>

2.5 资源路径处理

在项目开发中,我们经常会碰到要引入外部资源的需求,vue 单文件系统中,对资源引入路径有一定的特殊处理

  • 绝对路径前缀
  • 相对路径前缀
  • 特殊前缀

2.5.1 example02

\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
    <img src="../assets/logo.png" alt="">
  </div>
</template>
 
<script>
export default {
     
     
  name: 'HelloWorld',
  props: {
     
     
    msg: String
  }
}
</script>
 
 
<style scoped>
  p{
     
     
    color: red;
  }
</style>

Webpack会将其作为模块进行打包,然后把它构建生成到指定的目录里。

但现在有一个问题是,Webpack有一个http服务(Webpack server),它生成后把所有的编译内容都是存在内存中的,没有真正地生成文件,在这里是找不到最终打包的东西的(都在内存中)。

在这里插入图片描述

如果想上线开发完成了,这个时候才能使用build命令,对其进行构建,才能在硬盘中生成。

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.59
Branch: branch04

commit description:a1.59(example02——引入图片资源)

tag:a1.59

2.5.2 绝对路径前缀

就是以 /https://www.csdn.net/ 等这样的绝对路径开头的(不会被Webpack解析),不做任何处理,保持原样地址不动,直到被浏览器解析。

2.5.2.1 example03

2.5.2.1.1 example03-1

vue04\vue脚手架demo\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
    <img src="/assets/logo.png" alt="">
  </div>
</template>

<script>
  export default {
     
     
    name: 'HelloWorld',
    props: {
     
     
      msg: String
    }
  }
</script>


<style  scoped>
  p {
     
     
    color: red;
  }
</style>

现在暂时没有资源,所以访问不到图片。

在这里插入图片描述

这个时候就会保持原地址不变,直接交给浏览器处理,由于没这个资源,显然显示不出来。

实际上webpack会指定一个根目录(public/index.html),如果把它丢到public文件夹里。

在这里插入图片描述

\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
    <img src="/logo.png" alt="">
  </div>
</template>

src/assets/文件夹中文件是需要经过Webpack打包处理的,作为模块打包的,而public存放的文件是不需要经过Webpack打包处理的,而是通过浏览器发送http请求处理的资源。

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.60
Branch: branch04

commit description:a1.60(example03-1——相对路径引入图片资源)

tag:a1.60

2.5.2.1.2 example03-2

线上地址也不会被webpack处理,而是交给浏览器请求。

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
    <img src="https://csdnimg.cn/cdn/content-toolbar/dragonBoat-white.gif" alt="">
  </div>
</template>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.61
Branch: branch04

commit description:a1.61(example03-2——引入网上图片资源)

tag:a1.61

2.5.3 相对路径前缀

就是以 ./../ 这样的相对路径开头的,将会被看作相对的模块依赖,并按照你的本地文件系统上的目录结构进行解析,如:<img src="../a.png"> 解析后:<img src="require('../a.png')">,类似的还包括 background: url(...)@import

2.5.4 特殊前缀

  • 如果路径以 ~ 开头,其后的部分将会被看作模块依赖。这意味着你可以用该特性来引用一个 node(NPM 包) 依赖中的资源,如:<img src="~some-npm-package/a.png">
  • 如果路径以 @ 开头,也会被看作模块依赖。如果你的 webpack 配置中给 @ 配置了 alias,这就很有用了。所有 vue-cli 创建的项目都默认配置了将 @ 指向 /src

2.5.4.1 example04

如果使用相当路径,如果修改了引用资源文件的路径,也得修改资源路径,这样使用也不太好。

@ 开头,所有 vue-cli 创建的项目都默认配置了将 @ 指向 /src,也会被看作模块依赖。

无论我们的helloword组件移动到哪,都不会受到影响,都是表示src目录下的/assets/logo.png

\app\src\components\HelloWorld.vue

<template>
  <div class="hello">
    <p>这里是hello - {
   
   {msg}}</p>
    <img src="https://csdnimg.cn/cdn/content-toolbar/dragonBoat-white.gif" alt="">
    <img src="@/assets/logo.png" alt="">
  </div>
</template>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.62
Branch: branch04

commit description:a1.62(example04——@特殊前缀的使用)

tag:a1.62

3. 扩展

3.1 本地搭建服务

npx http-server --help 可看帮助

在这里插入图片描述

去npm搜指令:

在这里插入图片描述

npx http-server ./dist -c-l

在这里插入图片描述

在这里插入图片描述

3.2 自定义脚手架配置

官网有对应的配置:https://cli.vuejs.org/zh/config/#vue-config-js

在这里插入图片描述

我们之前用的都是默认配置,有的时候需要更改一些配置,这个时候可以单独创建一个vue.config.js文件,类似webpack.config

3.2.1 publicPath

  • Type: string

  • Default: '/'

    部署应用包时的基本 URL。用法和 webpack 本身的 output.publicPath 一致,但是 Vue CLI 在一些其他地方也需要用到这个值,所以请始终使用 publicPath 而不要直接修改 webpack 的 output.publicPath

    默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,例如 https://www.my-app.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 publicPath/my-app/

    这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,也可以用在类似 Cordova hybrid 应用的文件系统中。

    相对 publicPath 的限制

    相对路径的 publicPath 有一些使用上的限制。在以下情况下,应当避免使用相对 publicPath:

    • 当使用基于 HTML5 history.pushState 的路由时;
    • 当使用 pages 选项构建多页面应用时。

    这个值在开发环境下同样生效。如果你想把开发服务器架设在根路径,你可以使用一个条件式的值:

    module.exports = {
          
          
      publicPath: process.env.NODE_ENV === 'production'
        ? '/production-sub-path/'
        : '/'
    }
    

如:

\test01\app\vue.config.js

  • publicPath 默认为‘/’ —— 如果公司在一个项目上开发一些子项目,就可能有子目录了。
// vue.config.js
module.exports = {
    
    
    // 选项...
    publicPath: '/Web/subindex'
}

yarn serve

在这里插入图片描述
在这里插入图片描述

3.2.2 outputDir

  • Type: string

  • Default: 'dist'

    当运行 vue-cli-service build 时生成的生产环境构建文件的目录。注意目标目录在构建之前会被清除 (构建时传入 --no-clean 可关闭该行为)。

    提示

    请始终使用 outputDir 而不要修改 webpack 的 output.path

3.2.3 @assetsDir

  • Type: string

  • Default: ''

    放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。

    提示

    从生成的资源覆写 filename 或 chunkFilename 时,assetsDir 会被忽略。

如:

// vue.config.js
module.exports = {
    
    
    // 选项...
    publicPath: '/Web/subindex',
    assetsDir: './publicSource'
}

yarn build

在这里插入图片描述

在这里插入图片描述

3.2.4 indexPath

  • Type: string

  • Default: 'index.html'

    指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。

3.2.5 @filenameHashing

  • Type: boolean

  • Default: true

    默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。然而,这也要求 index 的 HTML 是被 Vue CLI 自动生成的。如果你无法使用 Vue CLI 生成的 index HTML,你可以通过将这个选项设为 false 来关闭文件名哈希。

3.2.6 @pages

  • Type: Object

  • Default: undefined

    在 multi-page 模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。其值应该是一个对象,对象的 key 是入口的名字,value 是:

    • 一个指定了 entry, template, filename, titlechunks 的对象 (除了 entry 之外都是可选的);
    • 或一个指定其 entry 的字符串。
    module.exports = {
          
          
      pages: {
          
          
        index: {
          
          
          // page 的入口
          entry: 'src/index/main.js',
          // 模板来源
          template: 'public/index.html',
          // 在 dist/index.html 的输出
          filename: 'index.html',
          // 当使用 title 选项时,
          // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
          title: 'Index Page',
          // 在这个页面中包含的块,默认情况下会包含
          // 提取出来的通用 chunk 和 vendor chunk。(首页当中提取的js)
          chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 如果还有其他页面,可继续往下配置,根pages一样  
        // 当使用只有入口的字符串格式时,
        // 模板会被推导为 `public/subpage.html`
        // 并且如果找不到的话,就回退到 `public/index.html`。
        // 输出文件名会被推导为 `subpage.html`。
        subpage: 'src/subpage/main.js'
      }
    }
    

    提示

    当在 multi-page 模式下构建时,webpack 配置会包含不一样的插件 (这时会存在多个 html-webpack-pluginpreload-webpack-plugin 的实例)。如果你试图修改这些插件的选项,请确认运行 vue inspect

3.2.7 devServer

  • Type: Object

    所有 webpack-dev-server 的选项都支持。注意:

    • 有些值像 hostporthttps 可能会被命令行参数覆写。
    • 有些值像 publicPathhistoryApiFallback 不应该被修改,因为它们需要和开发服务器的 publicPath 同步以保障正常的工作。

3.2.8 @devServer.proxy

  • Type: string | Object

    如果你的前端应用和后端 API 服务器没有运行在同一个主机上,你需要在开发环境下将 API 请求代理到 API 服务器。这个问题可以通过 vue.config.js 中的 devServer.proxy 选项来配置。

    devServer.proxy 可以是一个指向开发环境 API 服务器的字符串:

    module.exports = {
          
          
      devServer: {
          
          
        proxy: 'http://localhost:4000'
      }
    }
    

    这会告诉开发服务器将任何未知请求 (没有匹配到静态文件的请求) 代理到http://localhost:4000

    如果你想要更多的代理控制行为,也可以使用一个 path: options 成对的对象。完整的选项可以查阅 http-proxy-middleware

    module.exports = {
          
          
      devServer: {
          
          
        proxy: {
          
          
          '/api': {
          
          
            target: '<url>',
            ws: true,
            changeOrigin: true
          },
          '/foo': {
          
          
            target: '<other_url>'
          }
        }
      }
    }
    

3.2.9 vue-router—分析install源码

npm install vue-router

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.63
Branch: branch04

commit description:a1.63(安装vue-router)

tag:a1.63

我们看一下打包之前的index.js源码

这里导出去了VueRouter,这里面有一个方法是install,其实既可以传函数,又可以传包装install方法的对象,如果传的是函数,它就直接执行了。如果传的是对象,就会找对象底下的install方法,去调用它。最终vue的使用则是:Vue.use(VueRouter),之后就会执行它底下的install方法了,进行插件安装了。

在这里插入图片描述

重点看install方法源码实现 => 大概分析一下

import View from './components/view'
import Link from './components/link'
 
export let _Vue
 
export function install (Vue) {
    
    
    // 判断插件是否安装了,如果安装了,并且_Vue === Vue,即use多次,不会重复执行install (单例模式)
  if (install.installed && _Vue === Vue) return
  install.installed = true
 
  _Vue = Vue
 
  // 判断变量v是否定义过
  const isDef = v => v !== undefined
 
  // 注册实例 vm:组件对象  vm.$options 组件对象的配置选项
  // vm.$options._parentVnode 父组件
  const registerInstance = (vm, callVal) => {
    
    
    let i = vm.$options._parentVnode
    // 判断父组件是否注册过,对i进行赋值,赋完值判断data是否存在,判断路由实例是否注册过
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
    
    
      // 都判断过了,就会调用父组件的_parentVnode,并把vm组件对象实例及callVal传过去
      i(vm, callVal)
    }
  }
 
  // 做事,每一个组件及子组件,只要有组件一渲染就首先调用路由底下的beforeCreate方法
  Vue.mixin({
    
    
    beforeCreate () {
    
    
        // 判断创建的Vue对象配置有没有router属性对象,如果有则进行设置及处理
      if (isDef(this.$options.router)) {
    
    
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
    
    
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
     // 销毁该实例
    destroyed () {
    
    
      registerInstance(this)
    }
  })
 
   // $router 获取路由对象
  Object.defineProperty(Vue.prototype, '$router', {
    
    
    get () {
    
     return this._routerRoot._router }
  })
 
  // $route 获取当前匹配的路由对象
  Object.defineProperty(Vue.prototype, '$route', {
    
    
    get () {
    
     return this._routerRoot._route }
  })
 
  // 创建两个组件
  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)
 
  // 创建相关生命周期
  const strats = Vue.config.optionMergeStrategies
  // use the same hook merging strategy for route hooks
  strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}


(后续待补充)

猜你喜欢

转载自blog.csdn.net/u013946061/article/details/107731058
今日推荐