乐趣区

关于vue.js:Vue学习笔记四-久处不厌

原本打算写 JavaFX 的,然而比拟令人悲伤的是,那一篇博客没有同步到 GitHub 上,还在公司的电脑上。这篇还在。

前言

学习本篇须要有肯定的 Vue、Node、HTML、JavaScript、CSS 根底,须要一些预置概念。

《Vue 学习笔记 (一) 初遇篇》介绍 Vue 的源起以及 Vue 的根本示例,《Vue 学习笔记(二) 相识篇》对《Vue 学习笔记(一) 初遇篇》进行重构,从新组织了《Vue 学习笔记(一) 初遇篇》的内容: 随着网页越来越简单,开发者们在谋求越来越快的开发速度和性能,这也就是古代框架的缘起,绝对于 JQuery 这样间接操纵 DOM 结点的库,导致页面重绘影响页面的性能。古代前端框架推出了虚构 DOM 不再让开发者间接操纵 DOM 结点,同时引入了响应式、模板语法进一步放慢开发前端页面的速度,然而仅仅如此还不够,古代前端框架开始谋求可复用性,这也就是组件,JavaScript、CSS、HTML 的复合体,让咱们能够复用逻辑、款式、性能。

当初咱们来回顾一下《Vue 学习笔记(三)》,这篇文章外面咱们讲了事件零碎、监听事件、模块化、模块化的益处。以及 JavaScript 的模块化倒退历史,JavaScript 的如何应用模块, 表单的输出与绑定、组件的简略应用。但对于 Vue 的外围概念组件来说咱们并未介绍多少,咱们只是让她小小的露了个面,演示了一个组件如何申明,如何应用。但这种应用组件的形式并不讨喜,起因在于这种形式的组件的内容: HTML、CSS、JavaScript 都在字符串外面。比拟适应的是逻辑、款式都不简单的场景,一旦这些内容略微宏大一点点,宏大的字符串就会让咱们头晕脑胀。

对此的解决方案是单文件组件,将文件放在一个文件中,后缀为.vue。但咱们想接着开发前端利用还不大够,你会发现前面单文件利用基本上都会抉择用 Vue CLI 来构建, 那 Vue CLI 是什么?Vue 咱们是意识的,那 CLI 呢?首先 CLI 是 Commend-Line Interface 的缩写, Commend-Line Interface 命令行界面,用户通过键盘输入指令,计算机接管指令后,予以执行。下面是维基百科的定义,上面咱们来看下 Vue CLI 是如何介绍本身的:

Vue CLI 是一个基于 Vue.js 进行疾速开发的残缺零碎,提供:

  • 通过 @vue/cli 实现的交互式的我的项目脚手架。
  • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
  • 一个运行时依赖 (@vue/cli-service),该依赖:

    • 可降级;
    • 基于 webpack 构建,并带有正当的默认配置;
    • 能够通过我的项目内的配置文件进行配置;
    • 能够通过插件进行扩大。
  • 一个丰盛的官网插件汇合,集成了前端生态中最好的工具。
  • 一套齐全图形化的创立和治理 Vue.js 我的项目的用户界面。

Vue CLI 致力于将 Vue 生态中的工具根底标准化。它确保了各种构建工具可能基于智能的默认配置即可安稳连接,这样你能够专一在撰写利用上,而不用花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

咱们再来回顾一下《让咱们来来前端工程化》探讨了什么:

随着浏览器页面的越来越简单,许多问题变浮现了进去,兴许许多事件都是这样,当问题的规模比拟小的时候,通常比拟容易解决。一旦问题的规模开始增长,问题的解决难度也随着上涨。页面越来越简单,那就意味着代码量也在回升,晚期的页面简略,JavaScript 的设计者没有为这门语言筹备模块化,尽管语言自身没有自带,JavaScript 社区就自发的为 JavaScript 设计模块,比拟为人所熟知的模块化零碎是:

  • AMD —— 最古老的模块零碎之一,最后由 require.js 库来实现。
  • CommonJS —— 为 Node.js 服务器创立的模块零碎。
  • UMD —— 另外一个模块零碎,倡议作为通用的模块零碎,它与 AMD 和 CommonJS 都兼容。

当初,它们都在缓缓成为历史的一部分,但你依然能够在旧有的我的项目找到它们,语言级别的模块零碎在 2015 年的时候呈现在了规范 (ES6) 中,尔后逐步倒退,当初曾经失去了所有支流浏览器和 Node.js 的反对。模块化解决了在 JavaScript 如何复用代码的问题,从肯定水平上来说升高了代码量和代码复杂度。但这仅仅解决了一个问题,另一个值得注意的问题是,在应用了 npm 的状况下,最终的页面该如何交付,开发页面的时候咱们还有 CSS、SASS、JPG 等各种资源,咱们该如何组织这些文件,WebPack 是这个问题的一个答案,WebPack 会剖析 JavaScript 之间的依赖关系,将咱们我的项目的文件进行分类,放到对应的文件夹里。WebPack 这是一个打包工具,它提供的能力还有模块捆绑,所谓模块捆绑指的是将页面所需的模块捆绑后能力一个大文件或几个文件以缩小申请数量。

除此之外,还须要面对的问题是适配低版本浏览器的问题(IE 浏览器走开),有些 JavaScript 语法好用然而低版本的不反对,但能不能咱们只写一套,由工具帮咱们主动产生低版本浏览器的代码呢?这也就是 Babel。

为了疾速高质量的构建我的项目,咱们引入了一个又一个工具,然而该如何疾速的搭建起一个我的项目的模板呢?咱们的愿景是这些的通过一些命令行命令就能将 webpack、node.js、babel 都引入到我的项目中,并且这些外面曾经写了一些默认配置,有一个简略的示例。我只须要写我须要的页面就行了。这也就是 Vue CLI。

再读一遍 Vue 自我介绍的话:

Vue CLI 致力于将 Vue 生态中的工具根底标准化。它确保了各种构建工具可能基于智能的默认配置即可安稳连接,这样你能够专一在撰写利用上,而不用花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

开启第一个单文件我的项目吧

本我的项目首先须要一个 node 环境,要求 Node 的版本在 14.18.1 以上,尽管 Vue 的最新大版本曾经到了 3.2 了,但咱们这里的 Vue 大版本抉择还是 2.5.2。前面会专门再钻研 3 和 2 的区别。咱们本次借助 Vue CLI 来构建我的项目,咱们借助 VS Code 来编写代码,我的 VS Code 装置的插件有:

  • vue-helper: Vue 代码提醒和组件跳转。

第一步关上 VS Code, 点击终端, 在终端中输出命令:

# 这个命令代表的意思是全局装置 vue cli
npm install --global @vue/cli

而后在终端外面输出:

# Vue 脚手架就会帮咱们创立一个叫 my-project 的我的项目
# 在创立过程中会给你一些抉择,比方输出我的项目形容啊之类的
vue init webpack my-project

我的项目构造

最终的我的项目构造如下图所示:

  • .eslintrc.js:代码检测工具, 对立代码格调
  • .babellrc: 能够在 JavaScript 应用新个性,并在生产环境将其转换为能够跨浏览器运行的旧代码,也能够在外面配置 babel 插件。
  • package.json: npm 的配置文件,在这里咱们能够援用第三方 JavaScript 库。
  • .postcssrc.js: 能够应用 CSS 中应用新个性,并在生产环境将其转换为能够跨浏览器运行的代码。
  • src: 这个是 Vue 利用的外围目录

    • main.js:这是利用的入口文件。目前它会初始化利用并且指定将利用挂在到 index.html 文件中的哪个 HTML 元素上。通常还会做一些注册全局组件或者增加额定的 Vue 库的操作。
    • App.vue: 这是 Vue 利用的根结点组件,目前外面会有一个示例组件。
    • assets: 这个目录用来寄存像 CSS、图片这种动态资源。然而他们放在代码目录上面,所以能够应用 webpack 来操作和解决。

      ## 运行 Vue 我的项目

之前我用 Vue 写的页面都是在 html 外面,咱们间接用浏览器关上即可。那当初的我的项目咱们该如何看页面成果呢?咱们在终端里输出 npm run dev 即可, 像上面的图一样:

实质上执行的还是

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

而后在控制台就能够看到:

而后咱们在浏览器拜访这个地址:

开启第一个组件

先来温习一下什么是组件,在 Vue 3 的中文文档倒是没给出定义, 只是简略阐述了一下:

组件容许咱们将 UI 划分为独立的、可重用的局部,并且能够对每个局部进行独自的思考。

如同说了什么,又如同什么都没说,既然 Vue 的中文文档没给出组件的定义(也可能是我没看到),那咱们这里就尝试斟酌出一个定义, 在网页中咱们通常并不止应用 HTML,咱们用 html 搭建根本的内容骨架,用 CSS 对内容骨架进行丑化,用 JavaScript 为实现业务逻辑和页面管制。当咱们想要复用的时候通常是三者都想复用,而不仅仅是复用其中一项,基于此咱们尝试给出组件的定义就是:

一种蕴含内容 (HTML)、款式(CSS)、逻辑(JavaScript) 的组合体。

咱们来直观感受一下组件, 在咱们方才建设的我的项目中就有一个组件,在 src/components 上面,它叫 HelloWorld.vue, 外面的内容如下所示:

<template>
  <div class="hello">
    <h1>{{msg}}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li>
        <a
          href="https://vuejs.org"
          target="_blank"
        >
          Core Docs
        </a>
      </li>
      <li>
        <a
          href="https://forum.vuejs.org"
          target="_blank"
        >
          Forum
        </a>
      </li>
      <li>
        <a
          href="https://chat.vuejs.org"
          target="_blank"
        >
          Community Chat
        </a>
      </li>
      <li>
        <a
          href="https://twitter.com/vuejs"
          target="_blank"
        >
          Twitter
        </a>
      </li>
      <br>
      <li>
        <a
          href="http://vuejs-templates.github.io/webpack/"
          target="_blank"
        >
          Docs for This Template
        </a>
      </li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li>
        <a
          href="http://router.vuejs.org/"
          target="_blank"
        >
          vue-router
        </a>
      </li>
      <li>
        <a
          href="http://vuex.vuejs.org/"
          target="_blank"
        >
          vuex
        </a>
      </li>
      <li>
        <a
          href="http://vue-loader.vuejs.org/"
          target="_blank"
        >
          vue-loader
        </a>
      </li>
      <li>
        <a
          href="https://github.com/vuejs/awesome-vue"
          target="_blank"
        >
          awesome-vue
        </a>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {msg: 'Welcome to Your Vue.js App'}
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {font-weight: normal;}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {color: #42b983;}
</style>

咱们来简略的看一下这个组件的组成:

  • template(html 内容)
  • script(JavaScript 行为): 在这个组件中, 咱们只导出了该组件, 名字是 helloWorld。留神到之前咱们写的示例 data 是一个对象,当初 data 是一个函数而且必须是一个函数,这样各个组件就可能互不影响。
  • style: 款式

那咱们该如何应用这个组件呢,首先咱们 App.vue 中引入该组件, 而后再注册:

import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {HelloWorld}
}

而后咱们在 App.vue 中间接将这个组件名当标签一样应用即可,像上面这样:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
    <hello-world/>
    <hello-world/>
  </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 利用中十分重要的一部分。组件能够把一个很大的应用程序拆分成独立创立和治理的不相干区块,而后彼此按需传递数据,这些小的代码块能够不便更容易的了解和测试。

Vue 把模板、相干脚本和 CSS 一起整合放在.vue 结尾的一个单文件中。这些文件最终会通过 JavaScript(前面统称为 JS)打包工具 (如 Webpack) 解决,这意味着你能够应用构建工具来实现更多简单的组件,比方 Babel、TypeScript、SCSS。

待办表单组件

留神下面咱们的一句话:

组件能够把一个很大的应用程序拆分成独立创立和治理的不相干区块,而后彼此按需传递数据,这些小的代码块能够更不便更容易了解和测试。

这其实在说的是, 咱们将利用拆分为若干组件,那组件之间如何传递数据,咱们将在上面的例子中演示,这个例子来自 MDN Web docs,地址是:

https://developer.mozilla.org…

前面的介绍也多基于这个例子,只不过会退出一点我集体的了解。方才那个组件来自 Vue CLI,当初让咱们本人创立一个组件,首先咱们在 src/components 目录下建设一个 ToDoItem.vue。而后再这个文件下建设三个标签: template、script、style。像上面一样:

<template>
  
</template>

<script>
export default {

}
</script>

<style>

</style>

当初让咱们来丰盛这个组件的内容:

<template>
  <div>
     <input type="checkbox" id="todo-item" checked="false"/>
     <label for="todo-item"> 我的待办 </label>
  </div>
</template>

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

<style>

</style>

而后咱们在 App.vue 中应用这个组件,要应用一个组件,是固定的步骤,第一步引入这个组件,第二步注册这个组件:

<template>
  <div id="app">
    <h1>To-Do List</h1>
  <ul>
    <li>
      <to-do-item></to-do-item>
    </li>
  </ul>
  </div>
</template>

<script>
import ToDoItem from './components/ToDoItem.vue'
export default {
  name: 'App',
  components: {ToDoItem}
}
</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>

成果如下:

但目前来说咱们的组件还是有些板滞,他不大聪慧,按照 HTML 标准,ID 必须惟一,咱们只能在页面上蕴含一次。但因为浏览器的宽容,你会发现蕴含两次也照样能渲染进去。除此之外,label 标签的内容是固定的,这不是动静的。那如何让这个组件聪明起来呢,这也就是 props

props

在 Vue 中,注册 props 的形式有两种:

  • 以字符串数组的形式列出 props,数组中的每个实体对应一个 prop 名称。
Vue.component('my-component',{
    // 申明 props
    props:['message'],
    // 在模板中应用绑定语法来绑定到 prop
template: '<div>{{message}}</div>'
}) 
  • 将 props 定义为一个对象,每个 key 对应于 prop 名称。将 props 列为对象能够指定默认值,将 props 标记为 required,执行根本的对象类型(特地是 JavaScript 根本类型),并执行简略的 prop 校验。

留神:prop 验证只能在 development 模式下进行,所以你不能在生产环境中严格依赖它。此外,prop 验证函数在组件实例创立之前被调用,因而它们不能拜访组件状态 (或其余 props)

Vue.component('my-component', {
  // 申明 props
  props: {
    message: {
      type: String,
      default: 'Hello'
    }
  },
  template: '<div>{{message}}</div>'
})

对于针对 ToDoItem 组件,咱们将应用对象注册法,咱们在默认导出的对象 {} 对象上增加一个 props 对象,该 props 属性含有一个空对象。在这个对象外面咱们增加两个 key 为 label 和 done 属性。label 的值应该是一个带有两个属性的对象,第一个是 required 属性,如果它的值是 true。那么这就相当于通知 Vue 说,每个该组件的实例必须有一个 label 字段。如果没有,Vue 提醒会给出正告。第二个是增加一个 type 属性,如果它的值是 String 类型,这等于在通知 Vue,咱们心愿 type 属性的值是 String 类型。

当初转向 done prop,首先增加一个 default 属性,默认值是 false,这意味着当没有给 ToDoItem 组件传递 done prop,done prop 的值会是 false。default 不是必须的,咱们只在非 required 里才须要 default。而后增加一个 type 属性,值为 Boolean,这将通知 Vue,咱们心愿这个 Prop 的值是 JavaScript 的 Boolean 类型。当初 ToDoItem 的 script 变成了上面这样:

<script>
export default {
  name: 'ToDoItem',
  props: {label: {required: true, type: String},
    done: {default: false, type: Boolean}
  }
}
</script>

当初组件申明了它所须要的值,咱们就能够在 template 外面应用这些变量值,像上面这样:

<template>
  <div>
     <input type="checkbox" id="todo-item" checked="false"/>
     <label for="todo-item"> {{label}}</label>
  </div>
</template>

再次运行我的项目,你会发现浏览器的控制台会输入正告:

[Vue warn]: Missing required prop: "label"
found in
---> <ToDoItem> at src/components/ToDoItem.vue
       <App> at src/App.vue
         <Root>

这是因为咱们在 ToDoItem 将 label prop 标记为必传,然而咱们在应用这个组件的时候却没有传入。当初让咱们来修复这个问题,在应用这个组件的试验传递进去:

<template>
  <div id="app">
    <h1>To-Do List</h1>
  <ul>
    <li>
      <to-do-item label="hello prop" done="true"></to-do-item>
    </li>
  </ul>
  </div>
</template>

<script>
import ToDoItem from './components/ToDoItem.vue'
export default {
  name: 'App',
  components: {ToDoItem}
}
</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>

实际效果:

后面咱们提到, html 的标签的 id 不容许反复,如果你反复了,没问题的起因在于浏览器比拟宽容。当初咱们来尝试为 label 的 for 和 input 的 id 产生惟一值,在我的项目中咱们用到了 npm,这意味着咱们能够大量应用第三方库,咱们这里用来产生惟一 id 的库叫 lodash,首先咱们在终端外面尝试装置它:

npm install --save lodash.uniqueid

而后在 script 标签外面引入:

import uniqueId from 'lodash.uniqueid';

而后在 data 外面申明一个 id,并将 data 的 id 和复选框的 id、标签的 for 属性进行绑定,如下所示:

<template>
  <div>
     <input type="checkbox" :id="id" :checked="isDone"/>
     <label :for="id"> {{label}}</label>
  </div>
</template>

<script>
import uniqueId from 'lodash.uniqueid'
export default {
  name: 'ToDoItem',
  props: {label: {required: true, type: String},
    done: {default: false, type: Boolean}
  },
  data () {
    return {
      isDone: this.done,
      id: uniqueId('todo-')
    }
  }
}
</script>

<style>

</style>

而后关上浏览器察看源码为发现,label 的 for 和复选框的 id 都产生了惟一键。

总结一下

在《让咱们来来前端工程化》咱们简略探讨了前端工程化,工程化的一个标记就是引入越来越多的工具,而 Vue CLI 则将这些工具一站式集成,通过一行命令咱们就能轻易的集成这些工具,简略的搭建一个前端工程。组件能够把一个很大的应用程序拆分成独立创立和治理的不相干区块,而后彼此按需传递数据,这些小的代码块能够不便更容易的了解和测试。当咱们将应用程序拆分,那随之随同而来的一个问题就是组件之间该如何通信,这里咱们通过一个小的待办组件,介绍了父子组件之间传递数据的形式,也就是 props。

参考资料

  • mdn web docs https://developer.mozilla.org…
退出移动版