目录 §

  • 0. Vue前置知识与学习路线 §
  • 1. Vue项目搭建 §
  • 2. @vue/cli §
  • 3. Vue实例 +1 demo §
  • 4. 使用Vue实例 §
  • 5. vue.jsvue.runtime.js 的区别和使用方法 §
    • templaterender
  • 6. Vue实例2 井字游戏 §
  • 7. 用 codesandbox.ioVue 代码 §
  • 8. VuePress §
  • 9. 总结 §

[toc]


0. Vue前置知识与学习路线 §

  • Node.js已安装
  • HTML/CSS/JS语法
  • Vue文档收藏 中文文档
  • 利用文档的搜索功能快速定位
  • 学习路线
  • 需要学的vue | @vue/cli | vuex | vue router | axios

系统学习 Vue

  • CRM,过一遍文档,总结为博客
  • 目录学习法
  • 面试官提问学习法
  • 关键词:Vue 实例el 和 dataVue 简单数据变动管理
  • 注意对比vue2.xvue3.x

目标一:搞出一个使用Vue的项目

1. Vue项目搭建 §

方法一:使用Vue CLI (@vue/cli)

  • 是基于 Vue.js 进行快速开发的完整系统(实现的交互式的项目脚手架)
  • 搜索@vue/cli文档
  • 在终端里使用 vue 相关命令
  • 「创建一个项目」CRM

方法二:手动配置,从零搭建

  • 使用webpackrollup从零搭建,较复杂
  • 使用Vitesnowpack从零搭建

方法三:第三方在线傻瓜配置,适合demo

  • codeSandBox
  • codePen
  • 详见codesandbox.ioVue 代码 §

2. @vue/cli §

  • CRM @vue/cli提到的工具官网示例
  • 通过 vue ui 通过一套图形化界面管理所有项目

CLI 服务 (@vue/cli-service) 是一个开发环境依赖,局部安装在每个 @vue/cli 创建的项目中

  • CLI 服务是构建于 webpackwebpack-dev-server 之上。它包含
    • 加载其它 CLI 插件的核心服务;
    • 一个针对绝大部分应用优化过的内部的 webpack 配置;
    • 项目内部的 vue-cli-service 命令,提供 servebuildinspect 命令

@vue/cli用法

全局安装,使用 npm 或 yarn

1
2
3
yarn global add @vue/cli
#或
npm install -g @vue/cli

查看版本与环境

1
2
vue --version
vue info

创建目录(新项目的脚手架)

1
vue create <path/name>
  • 路径<path>可用点 ./

按提示选择配置

  • 提示选取一个 preset
  • 可选默认的包含了基本的 Babel + ESLint 设置的 preset
  • 也可以选“手动选择特性”来选取需要的特性
    • 这个默认的设置非常适合快速创建一个新项目的原型
    • 而手动设置则提供了更多的选项,它们是面向生产的项目
  • 选择配置操作: (回车为进行下一步,↑↓键将光标上下移动选择,空格键选择或取消勾选)
  • 目前方法 present:
    • Manually select features
  • 包含特征 features:
    • Babel
    • CSS Pre-processors
    • Linter / Formatter
    • Unit Testing
  • CSS 预处理器 CSS pre-processors:
    • Sass/SCSS (With dart-sass)
  • 代码校验/格式化 Linter / Formatter:
    • ESLint with error prevention only
  • 何时触发校验 additional lint features:
    • Lint and fix on commit
  • 单元测试方案 unit testing solution:
    • Jest
  • 如何设置配置文件 prefer placing …:
    • In dedicated config files
  • 是否把以上选项作为以后项目的默认配置 save this as …:
    • N
  • 最后一步选N不要保存默认配置 ? Save this as a preset for future projects? (y/N) N

本demo的@vue/cli配置选项

  • 选错 Ctrl + c中断重来
  • 注意默认选项
  • 仅对此demo适用,自行斟酌真实项目的配置
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
Vue CLI v4.4.6
? Please pick a preset: (Use arrow keys)
  default (babel, eslint)
> Manually select features
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project:
>(*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors
 (*) Linter / Formatter
 (*) Unit Testing
 ( ) E2E Testing
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
> Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
  Less
  Stylus
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: (Use arrow keys)
> ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: Basic
? Pick additional lint features:
 ( ) Lint on save
>(*) Lint and fix on commit
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint and fix on commit
? Pick a unit testing solution:
  Mocha + Chai
> Jest
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint and fix on commit
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
  In package.json
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint and fix on commit
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) N
########################################
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, CSS Pre-processors, Linter, Unit
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass
)
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint and fix on commit
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
? Pick the package manager to use when installing dependencies: (Use arrow keys)
> Use Yarn
  Use NPM
########################################
.....
########################################
success Saved lockfile.
Done in 21.23s.
⚓  Running completion hooks...

�  Generating README.md...

�  Successfully created project vue-demo-2.
�  Get started with the following commands:

 $ cd vue-demo-2
 $ yarn serve

  • 根据提示进行下一步
  • 忽略警告warning
  • 如果发现错误error google
  • 进入目录,运行yarn serve
  • 自动开启一个本地预览服务器webpack-dev-server来检查项目是否成功创建

运行yarn serve自动生成后的目录结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
vue-demo-1
├── node_modules
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── assets
│   ├── components
│   ├── App.vue
│   └── main.js
├── test\unit
│   └── example.spec.js
├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── babel.config.js
├── jest.config.js
├── package.json
├── README.md
├── vue.config.js
└── yarn.lock

项目创建成功提示

1
2
3
# App running at:
# - Local: http://localhost:8080/ (端口号可能不一样)
# - Network: http://192.168.31.107:8080/
  • WebStormVSCode打开项目

目标二:做一个简单项目,熟悉涉及的文档

3. Vue实例 +1 demo §

需求实现:在 div 里实现一个展示数字的字符串 ,按下+1按钮,更新 data 中数据的内容


CRM 改App.vue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
  <div id="app">
    {{n}}
    <button @click="add">+1</button>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      n: 0,
    };
  },
  methods: {
    add() {
      this.n += 1;
    },
  },
}
</script>

<style lang="scss">
#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>

main.js

1
2
3
new Vue({
    render: h => h(App),
}).$mount('#app')

demo1小结

通过这个简单的demo,初步了解以下五个知识点

  1. el
  2. data(){}
  3. methods:{}
  4. 插值表达式{{n}}
  5. @click="add"
  6. 为什么可以直接导出export default {}

带着疑问查文档,实例接收配置项

  • el:实例负责管理的一个区域。如el: '#app' ,即让这个Vue实例去接管 idappDOM元素标签里的所有内容
  • data:定义了需要传递的一些数据。如 data: { content: 'hello world' } ,即传递了内容为 'hello world' 的数据:content 。这种数据在 dom 元素中用 {{ }} 来来调用对应数据内容
  • 少了 idVue 实例无法接管一个不用 el 管理的区域,说明 Vue 实例 接管了 el 管理下的 DOM 元素标签下的所有内容,没有被 el 管理过的 dom元素无法显示对应数据

4. 使用new Vue实例对象 §

类比jQuery实例对象const $div = new jQuery('#xxx')

  • $div封装了对#xxx所有操作,可省略为const $div = jQuery('#xxx')const $div = $('#xxx')

main.js

1
2
3
4
5
6
7
8
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
  • 同样的,const vm = new Vue()
  • vm封装了实例对于组件的所有操作
  • 封装了对 DOM 的所有操作,封装了对 data 的所有操作
  • 数据、事件绑定、等
  • 初始化./public/index.html中的<div id="app"></div>
  • 改掉默认的,对#app进行一个MVC的封装

main.js

1
2
3
4
import Vue from 'vue'
new Vue({
  el: '#app'
})

CRM改./public/index.html

1
 <div id="app">{{n}}</div>
  • 运行yarn serve
  • 报错[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
  • 提示要么使用loader预编译,要么使用完整版,默认使用运行时版
  • 安装方法 直接用 <script> 引入CDN

vue有两种形式的代码 compiler(模板)模式和 runtime 模式(运行时)

  • vue模块的package.jsonmain字段默认为runtime模式, 指向了"dist/vue.runtime.common.js"位置
  • 而在main.js文件中,初始化vue使用的是compiler模式,所以就会出现上面的错误信息

  • 直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量
  • 在开发环境下不要使用压缩版本,不然你就失去了所有常见错误相关的警告!
  • 开发版本包含完整的警告和调试模式
  • 生产版本删除了警告,33.30KB min+gzip
  • 各个引用文件的区别

vue2.x V.S. vue3.x

2.x中通过new Vue()的方法来初始化:

1
2
3
4
5
import App from './App.vue'
new Vue({
  store,
  render: h => h(App)
}).$mount('#app')

3.xVue不再是一个构造函数,通过createApp方法初始化:

1
2
import App from './App.vue'
createApp(App).use(store).mount('#app')

Vue的两个版本和三个使用方法

方法一:从HTML得到视图

  • 完整版Vue」,同时包含编译器和运行时的版本
  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码
  • 运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切
  • CDN引用完整版vue.js或完整生产版vue.min.js
  • 生产版中没有注释,体积小
  • 通过import引用vue.jsvue.min.js
  • 文档 「运行时环境 + 编译器 vs. 只包含运行时环境」
  • 使用bootCDN vue引入
  • 稳定版<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>

./public/index.html

1
2
3
4
5
6
7
<body>
  <div id="app">
  {{n}}
  {{message}}
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
</body>

main.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
new Vue({
  // 绑定页面元素 element
  el: '#app',
  data: {
    n: 0,
  }
  /*
  data(){
        return {
            msg:'hi'
        }
    }
  */
})
  • data定义可以是一个对象或是函数
  • data中的n对应index.html>#app内的模板数据{{n}}
  • 注意MVC的视图没有写在JS文件中,而是直接写在页面里index.html
  • 这就是完整版的功能:直接在页面中渲染数据

改为使用template,放页面内容

  • 页面元素可以放在html中,或放在template模板字符串中
  • 在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就将需要加上编译器,即完整版

./public/index.html

1
2
3
4
<body>
  <div id="app"></div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
</body>

main.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 需要编译器(完整版) main.js
new Vue({
  el: '#app',
  data: {
    n: 0,
    message: 'Dam Vue!',
  },
  template: `
    <div>{{message}} +1</div>
    <button @click="add">+1</button>
  `,
  methods: {
    add(){
    this.n +=1
    },
  },
})
console.dir(window.Vue);

./public/index.html

1
2
3
4
<body>
  <div id="app"></div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
</body>
  • 不直接写到HTML里面,而在JS写到template
  • 完整版可以直接在页面里写模板字符串
  • 在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板), 只包含运行时版(非完整版)不支持,而 完整版 支持

「非完整版」没有编译器,使用以上方法,页面中无渲染效果

不支持从HTML里获取视图,也不支持直接从template获取视图(不使用vue-loader

方法二:用JS构建视图

  • 使用「非完整版」,即vue.runtime.js,「运行时版」
  • 使用「运行时版生产版」,即vue.runtime.min.js
  • 引入运行时版<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
  • 不支持从html获取视图,使用template也不行
  • 通过 h()createElement 来创建 DOM
  • 不是给人(开发者)看的
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 「完整版」需要编译器
new Vue({
  template: '<div>{{ hi }}</div>'
})

// 「非完整版」不需要编译器
new Vue({
  render (h) {
    return h('div', this.hi)
  }
})
  • 用函数render(h){return h('xxx', this.xxxData)}
  • h就是对createElement的别名封装 alias
  • 运行时版存在的意义是,更加地独立,功能单一

main.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// eslint-disable-next-line no-undef
new Vue({
  el: '#app',
  data: {
    n: 0,
    message: 'Dam Vue!',
  },
  /*
  render(createElement) {
  const h = createElement
    return h('div', [this.n + this.message + ' ', h('button', { on: {click: this.add}},' +1s')])
  },
  */
  // 创建一个 div,div 里面是 n 和 button
  // button 的事件监听是 点击后触发 add方法,button 里面(的内容)是 Click me to add one
  render(h) {
    return h('div', [this.n + this.message + ' ', h('button', { on: {click: this.add}},' +1s')])
  },
  methods: {
    add() {
      this.n += 1
    }
  }
})
  • 不适合开发(实际是打包自动生成),代码不清晰
  • 体积小,适合生产环境

./public/index.html

1
2
3
4
5
<body>
  <div id="app">
  </div>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.runtime.min.js"></script>
</body>

「完整版」思路

  • 视图是写在HTML里或template选项的,由于有 compiler(编译器)的存在
  • vue用编译器compilerhtml字符串模板中的${{n}},转化为实际数据htmlDOM(复杂的编译v-ifv-for@click),数据改变this.n += 1时,渲染DOM节点
  • 编译器的代码复杂,占用一定的体积(相对「非完整版」+30%
  • 优点:编译器可以将含有占位符${{}}或者条件语句变成真实的DOM节点,可以从HTML得到视图
  • 不适用于生产环境

「非完整版」思路

  • 没有compiler,不直接编译${{n}}
  • 在JS中通过render()h()创建节点
  • 优点:没有compiler,所以体积小
  • 缺点2:没有compiler,不能将HTML变成节点,需要用JS构建视图
  • 缺点1:HTML就只有一个div#appSEO不友好

index.html中的<div id="app"></div>里面会被替换为Demo变异后的内容,但替换前是空的,这样SEO不友好

SEO友好

  • SEO(Search Engine Optimization),即搜索引擎优化
  • 可以将搜索引擎SEO理解为不停地curl网站源代码
  • 根据curl结果猜测页面内容,命令行中输入curl https://xiedaimala.com
  • 可以看到网址传回的结果

SEO不友好

  • 如果页面都是用JS创建的,搜索引擎curl无效(google除外),无法抓取信息

过时的解决方案


方法三:「非完整版」+ Vue的单文件组件*.vue

*.vue包含三个基本的标签,设置为snippets

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div>
    $1
  </div>
</template>

<script>
    export default {
        data() {
            return {
                $2
            }
        },
        methods: {
          $3
        }
    };
</script>

<style scoped>
</style>
  • 使用vue-loader时,export defaultdata必须使用函数的形式,必须有返回值
  • 创建一个vue文件

demo.vue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
  <div class="red">
    {{n}}
    <button @click="add">+1s</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      n: 0,
    };
  },
  /*
  render(h) {
    return h("div");
  },
   */
  methods: {
    add() {
      this.n += 1;
    },
  },
};
</script>

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

main.js导入单文件组件,实例中render(h) {return h(xxx)}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import Demo from "./Demo.vue"
console.log(Demo)
console.log(Demo.render.toString())
/*
// eslint-disable-next-line no-undef
new Vue({
  el: "#app",
  render(h) {
    console.log(h(Demo))
    return h(Demo)
  } // 渲染`<template>`中的内容
})
 */

// eslint-disable-next-line no-undef
new Vue({
  render(h) {
    return h(Demo)
  }
}).$mount('#app') // 挂载到#app上 代替 el: "#app"

vue-loader做了什么

  • 使用 vue-cli 时,已经配置好 webpackvue-loader
  • 使用webpackvue-loader,可以将.vue文件编译成h构建方法
  • yarn build后,将<div>${{n}}</div>转化为 render 函数的方法 (h('div', this.n)),客户端可解析的代码
  • 不需要在单文件组件中写render函数
  • vue-loader将较为直观的template内容预编译为h()
  • yarn build时转换,让用户下载只支持render的不完整版Vue和编译好的h('div', this.n)
  • 即将编译器放到vue-loader实现,vue-loader调用compiler
  • 使用 vue-loadervueify*.vue 文件内部的模板会在构建时预编译成 JavaScript
  • 在最终打好的包里实际上是不需要编译器,所以只用运行时版本即可
  • 用户下载产品时只需要下载体积小的非完整版
  • 开发人员编写代码时,也不需要使用 render 方法去构造元素

使用单文件组件*.vue

  • 单文件组件*.vue清晰地分为视图template、逻辑script、样式style
  • vue-loader将以上的三个部分编译成一个对象
  • Vue实例对象中声明属性el的节点目标、render(h) {return h(xxx)}xxx为导入的单文件组件

小结Vue实例作用

Vue实例如同jQuery实例

  • 封装对DOM的所有操作
  • 封装对data的所有操作

Vue操作DOM

  • 监听事件
  • 改变DOM

Vue操作data

  • 增删改查
  • Vue2的bug 响应式原理
  • Vue3的改进

Vue未封装ajax

  • axiosajax功能

vue内部过程

  1. 首先将vue中的模板进行解析解析成abstract syntax tree (AST)抽象语法树
  2. 将抽象语法树编译成render函数
  3. render函数再翻译成virtual DOM 虚拟DOM
  4. 将虚拟DOM显示在浏览器上

runtime-onlyruntime-compiler的区别

  • runtime-onlyruntime-compiler更快
    • 因为它省略了将vue中的模板进行解析解析成abstract syntax tree (ast)抽象语法树
    • 跳过将抽象语法树编译成render函数
    • 直接用render函数
  • 如果是runtime-compiler,那么main.js中就会出现template从而需要过程一导致增加了一个过程,同时增加了大小
  • runtime-only只能识别render函数,不能识别template
  • *.vue文件中的也是被 vue-template-compiler 编译成了 render函数,所以只能在*.vue里写 template
  • runtime-only 模式中把 template 放在了*.vue 的文件中, vue-template-compiler的在开发依赖时将*.vue文件中的 template 解析成 render 函数,因为是开发依赖,不在最后生产中,所以最后生产出来的运行的代码没有template

过程图解

  • template -> AST -> render -> vDOM -> UI
    • template 代码首先会解析成 AST(抽象语法树,abstract syntax tree
    • AST 编译成 render 函数
    • render 函数变化成 vDOM(虚拟DOMvirtual DOM
    • 最终 vDOM 的内容更新渲染到 UI 上。

所以

  • runtime-compiler 经历的是一个 template -> AST -> render -> vDOM -> 真实的DOM -> 页面 的过程
  • runtime-only直接使用了render函数,所以经历的是一个 render -> vDOM -> UI 的过程。
  • runtime-only 会省去一个 template -> AST -> render 的过程,也不再需要相关的compilerloader,从而这种方法搭建的项目性能更高,代码也更少,项目大小也更小。

目标三:深入理解 完整版 / 运行时版 区别

5. 理解vue.jsvue.runtime.js 的区别和使用方法 最佳实践 §

不同项比较 Vue完整版 Vue运行时版 评价
特点 compiler(编译器) compiler compiler多占约30%体积
视图 写在HTML/template选项 写在render函数里用h创建标签 h默认,是作者写好传给render的,可改为任意名字
cdn引入 vue.js vue.runtime.js 文件名不同,生成环境后缀为.min.js
webpack引入 需配置alias 默认使用此版 维护者配置好了,满足大多数开发需求特殊需求除外
@vue/cli引入 需额外配置 默认使用此版 维护者配置好了

完整版

  • 对应的文件名:vue.jsvue.min.js后者是压缩版,取消了注释和警告
  • 支持从html获取视图(DOM节点)
  • 支持template
  • compiler编译器

非完整版

  • 对应的文件名:vue.runtime.jsvue.runtime.min.js同上
  • 不支持从html获取视图
  • 不支持template,需要通过vue-loader 将组件中的template模板编译为render函数
  • 没有compiler编译器,体积会比完整版小30%

最佳实践

总是使用运行时版,配合vue-loadervue单文件组件,目的是让用户端空间占用空间最小,思路如下

  • 保证用户体验,用户对VUe的依赖使用,下载的JS文件体积更小(去掉开发环境的编译器、注释、压缩代码),但只支持h函数main.js里不支持template
  • 保证开发体验,使用webpackvue-loader,开发者可直接在vue单文件组件中写HTML标签,也支持h函数,打包时,自动转译
  • 编译工作让loader自动完成,vue-loadervue文件里的HTML标签转为h函数

引用错了会怎样

  • vue.js错用成了vue.runtime.js,无法将HTML编译成视图,后台会报错compiler(要么使用loader预编译,要么使用完整版)
  • vue.runtime.js错用成了vue.js,代码体积变大,vue.js有编译HTML功能,并不报错

template V.S. render

template: HTML 内容模板(<template>)元素是一种用于保存客户端内容机制,该内容在加载页面时不会呈现,但随后可在运行时使用 JavaScript 实例化,即提供模板占位符

可以包裹元素,这个template不会被渲染到页面上,因为它天生带有display: none;属性

  • Vue 中将一个字符串模板作为 Vue 实例的标识使用,模板将会替换挂载的元素,挂载元素的内容都将被忽略,除非模板的内容有分发插槽(v-slot

template在完整版

  • 在JS里面创建Vue实例,template属性里写模板字符
1
2
3
4
5
6
// 需要编译器(完整版) main.js
new Vue({
  template: '
  <div>${{n}}</div>
  '
})
  • 完整版支持直接在index.html文件里写视图,支持模板字符
  • 也支持在main.js里写,需要写到实例的template属性中

例如

  • index.html中添加一个idapp的标签<div id="app"></div>
  • 接着添加script标签,引入完整版的js文件
    • <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
  • 然后在main.js里,直接把html代码写入template选项中
1
2
3
4
5
6
7
8
9
 new Vue({
     el: '#app',
     template: `
        <div>{{n}}</div>
    `,
     data: {
         n: 0
     }
 })
  • 运行Vue后,它会直接把n0写入到app标签中
  • 需注意的是,template中至少要有一个根元素,不能是纯文本,否则会报错
  • 如果存在多个同级元素,没有根元素时,只会显示第一个元素

template在运行时版

  • 只在单文件组件*.vue里写 template
  • *.vue 文件中提供模版、方法和样式,在 main.jsnew Vue 实例化render(h) {return h(xxx)}xxx 为导入的单文件组件

render是渲染函数,它可以代替template创建HTML元素

  • render函数的参数也是一个函数,一般名为h,实际可以是任意(类似的有evente
  • 这个h就是封装过的createElement
  • render函数将createElement的返回值放到了HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
new Vue({
  el: "#app",
  render(h) {
    return h(
      'div',
      {
        class: { 'style1': true, 'style2': true },
        style: { color: '#fff', background: 'red' },
        on: {
          click: function () {
            console.log('render函数')
          }
        }
      },
      ['元素文本', h('div', '子元素文本')]
    )
  }
})
  • createElement这个函数中有3个参数
    • 第一个参数(必要参数):主要用于提供DOMHTML内容,类型可以是字符串、对象或函数(可以是一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数,必填,类型:{String | Object | Function}
    • 第二个参数(类型是对象,可选):用于设置这个DOM的一些样式、属性、传的组件的参数、绑定事件之类(包含模板相关属性,用于设置模板元素的属性或者事件,可选,类型:{Object}
    • 第三个参数(类型是数组,数组元素类型是VNode,可选):主要是指该结点下还有其他结点,用于设置分发的内容,包括新增的其他组件。注意,组件树中的所有VNode必须是唯一的(设置模板元素文本,或者创建子节点 类型:{String | Array}
  • h 函数的本质是createElement 函数,这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.jsmount 函数,渲染成真实 DOM 节点,并挂载到根节点上
  • 而之所以要 叫 h,根据作者解释是,来源于 hyper script
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
render (createElement) {
    return createElement(
      'comp-one',
      {
        ref: 'comp',
        on: { // 事件监听(一),这里是组件上监听,需要 $emit
          click: this.handleClick
        },
      },
      [
        createElement('span', {
          ref: 'span'
        }, this.value)
      ])
  }

render在完整版

  • 可用但不使用
  • 在实际开发中,由于 h 函数的参数比较复杂,通过使用 webpackvue-loader 能将单文件组件(以.vue 结尾的文件)转换为 h 函数所需要的参数

render在运行时版

1
2
3
4
5
6
// 不需要编译器(非完整版) main.js
new Vue({
  render (h) {
    return h('div', this.n)
  }
})
  • 渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode
  • 如果组件是一个函数组件,渲染函数还会接收一个额外的 context参数,为没有实例的函数组件提供上下文信息
  • js里使用render写视图,结构和逻辑越多,代码越不清晰,不适合直接开发,而是被动生成的代码

例如

  • index.html中添加一个idapp的标签<div id="app"></div>
  • 接着添加script标签,引入运行版的js文件
    • <script scr="https://cdn.bootcss.com/vue/2.6.11/vue.runtime.min.js"><script>
  • 然后在main.js里,用render函数来创建标签
1
2
3
4
5
6
7
8
9
new Vue({
  el: '#app',
  render(h){
    return h('div', this.n)
  },
  data: {
    n: 0
  }
})

单文件组件*.vue

  • 另一个方法是在js里引入单文件组件xxx后,render(h) {return h(xxx)},通过vue-loader编译
1
2
3
4
5
6
7
// 非完整版在webpack的Vue Loader (main.js)
import Demo from './Demo.vue'
new Vue({
  render(h){
    return h(Demo)
  }
})

6. Vue实例2 井字游戏 §


7. 用 codesandbox.ioVue 代码 §

CodeSandbox V.S. CodePen 生成一个可以在线编辑实时预览的 vue 项目

  • 不适合IDE的各种快捷操作
  • 无代码提示

特点

CodeSandbox

  • 支持导出项目打包下载Export to ZIP-解压免配置使用
  • 支持配置各种资源
  • 有清晰地目录结构
  • Sandbox 使用的是运行时版
  • 支持用提供的构建工具生成生产版代码

CodePen

  • 只支持一个单文件组件*.vue
  • 无文件目录
  • 支持配置简单的资源
  • 可将编辑和预览视图以代码链接的形式插入博客

8. 用 VuePress 写 文档 §


9. 总结 §

  • 先做,然后才能知道达到什么水平
  • 看文档时,多看一眼其他章节,用到时再回来细看
  • 迭代
  • 封装比使用更值钱



参考文章

相关文章


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名