03vue工程化与组件

183 阅读7分钟

1. 单页面应用程序

单页面应用程序(Single Page Application),简称 SPA,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。

2. vue-cli

2.1 什么是 vue-cil

vue-cliVue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。

引用自 vue-cli 官网上的一句话:程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。但现在官方推荐使用 create-vue 来创建基于 Vite 的新项目

中文官网:cli.vuejs.org

2.2 安装和使用

vue-clinpm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:

npm install -g @vue/cli

基于 vue-cli 快速生成工程化的 Vue 项目:

vue create 项目的名称

配置大概这样选即可:

在这里插入图片描述

运行项目,需要在项目文件夹下执行:

npm run serve

打开本地的服务器,显示出来的页面(默认页面)如下:

在这里插入图片描述

2.3 vue 项目的运行流程

2.3.1 简述

在工程化的项目中,vue 要做的事情很单纯:通过 main.jsApp.vue 渲染到 index.html 的指定区域中。

其中:

  • App.vue 用来编写待渲染的模板结构

  • index.html 中需要预留一个 el 区域

  • main.jsApp.vue 渲染到了 index.html 所预留的区域中

2.3.2 具体

我们在 src 文件夹下的 components 文件夹(专门存放其他模板文件)创建 Test.vue 来编写模板:

<template>
    <div>
        <h1>自定义</h1>
    </div>
</template>

然后我们可以看到 public 文件夹下的 index.html 文件有:

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

我们可以在 src 文件夹下的 main.js 来渲染结构:

import Vue from 'vue'
import App from './App.vue'
import Test from './components/Test.vue' // 导入自己的 Vue 文件

Vue.config.productionTip = false

// 创建 Vue 实例对象
new Vue({
  // 把 render 指定的组件渲染到 html 页面中 
  render: h => h(Test),
}).$mount('#app') // 渲染的是 id 为 app 的标签  

再次运行整个项目,发现自定义三个字被成功渲染到页面。

所以,再说一遍,我们是通过 main.js.vue 结尾的文件 渲染到 index.html 的指定区域中。

3. vue 组件

3.1 什么是组件化开发

组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。其实就是另一种函数,方便复用和维护。

3.2 vue 中的组件化开发

vue 是一个支持组件化开发的前端框架。

vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 和我们自己编写的 Test.vue 文件本质上就是 vue 的组件。

3.3 vue 组件的三个组成部分

3.3.1 介绍

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构

  • script -> 组件的 JS 行为

  • style -> 组件的样式

其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。

这是我们 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 lang="less">
#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>

3.3.2 template

vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。

注意:

  • templatevue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素
  • template 中只能包含唯一的根节点

3.3.3 script

vue 规定:开发者可以在 <script> 节点中封装组件的 JS 业务逻辑。

注意:

  • 组件相关的 data 数据, methods 方法,侦听器都需要定义在 script 里的 export default{} 所导出的对象中

  • vue 组件中的 data 必须是函数,不能直接指向一个数据对象。因此在组件中定义 data 数据节点时,下面的方式是错误的:

    data:{
    	num: 0 // 报错
    }
    

    这会导致多个组件实例共用同一份数据的问题。

    可以这样写:

    data(){
    	return {
    		num: 0
    	}
    }
    

3.3.4 style

vue 规定:组件内的 <style> 节点是可选的,开发者可以在 <style> 节点中编写样式美化当前组件的 UI 结构。

如果需要使用less,在 <style> 标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式

<style lang="less">
.box {
    width: 300px;
    height: 100px;
    background-color: bisque;
    font-size: 10px;
    text-align: center;
    line-height: 100px;

    h1 {
        color: blue;
    }
}
</style>

3.4 组件之间的父子关系

我创建了两个组件 Left.vueRight.vue,并且重写了原来的根组件 App.vue。组件在被封装好之后,彼此之间是相互独立的,不存在父子关系。

而当我们使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系。比如 Left.vueRight.vue 组件在根组件 App.vue 中使用,那么此时 App.vueLeftRight 组件的父亲,而 LeftRight 组件是兄弟关系。

3.5 使用组件的三个步骤

3.5.1 使用 import 语法导入需要的组件

// 1. 导入组件
import Left from "@/components/Left.vue"
import Right from "@/components/Right.vue"

注意:@ 默认为 src 文件夹

3.5.2 使用 components 节点注册组件

export default {
  components: {
    Left,
    Right
  }
}

注意:通过 components 注册的是私有子组件

例如:

在组件 A 的 components 节点下,注册了组件 F,则组件 F 只能用在组件 A 中;不能被用在组件 C 中。

请思考两个问题:

为什么 F 不能用在组件 C 中?

因为组件 A 的 components 节点下,注册的组件 F,是私有子组件,无法用在其他组件中

怎样才能在组件 C 中使用 F?

重新再 C 中 定义一个 components 节点注册组件 F,这方法可以但是,如果很多个组件都需要使用组件 F,那在这些组件都需要使用 components 节点注册组件 F 显得太过鸡肋和麻烦,所以我们有个新的概念:全局组件

vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

// 1. 导入 vue 组件
import Count from '@/components/Count.vue'

// 2. 设置为全局组件,左边为设置的组件名,右边为导入的组件
Vue.component('MyCount', Count)

3.5.3 以标签形式使用刚才注册的组件

使用全局组件:

<template>
    <div id="left">
        <h3>Left</h3>
        <MyCount></MyCount>
    </div>
</template>

3.6 组件的 props

3.6.1 概述

props 是组件的自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性!

它的语法格式如下:

export default {
  props:['自定义属性A','自定义属性B''自定义属性C'],
}

该属性可以使用的场景是:两个不同组件用了同一个子组件,然后需要给两个不同组件的子组件设立不同的初始值。

3.6.2 props 是只读的

vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错:

在这里插入图片描述

要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!

<template>
  <div>
    <h5>Count 组件</h5>
    <p>Count 组件的值为 {{ count }}</p>
    <button @click="count+=1">+1</button>
  </div>
</template>

<script>
export default {
  props:['init'],
  data() {
    return {
      count: this.init
    }
  }
}

3.6.3 props 的 default

在声明自定义属性时,可以通过 default 来定义属性的默认值。示例代码如下:

export default {
  props:{
    init:{
      default: 6
    }
  }
}

3.6.4 props 的 type

在声明自定义属性时,可以通过 type 来定义属性的值类型。示例代码如下:

export default {
  props:{
    init:{
      default: 6,
      type: Number
    }
  }
}

注意:如果传入的值和 type 类型不符,会报错

3.6.5 props 的 required

在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。示例代

码如下:

export default {
  props:{
    init:{
      type: Number,
      required: true
    }
  }
}

注意:即使设置默认值,没有传值也会报错

3.6.6 组件之间的样式冲突问题

1. 概述

默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  • 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
  • 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素

2. 解决1

给标签设定自定义属性,用属性选择器进行选择。

<template>
  <div>
    <h3 data-h3>Count 组件</h3>
    <p>Count 组件的值为 {{ count }}</p>
    <button @click="count+=1">+1</button>
  </div>
</template>


<style>
h3[data-h3]{
  color: red;
}
</style>

3. 解决2

虽然方法一也可以行,但我们如果有多个标签需要命名多个自定义属性,开发较为麻烦。为了提高开发效率和开发体验,vuestyle 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题:

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

我们查看 DOM 结构,发现该组件所有的标签都添加了一个自定义属性。

在这里插入图片描述

不仅如此,该组件的样式也被添加了该自定义属性:

在这里插入图片描述

这很合理因为我只在该组件使用该样式。

4. 解决 2 存在的问题

如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。

<style scoped lang="less">
/* 不加/deep/ 时,生成的选择器为 h3[data-v-3f581d8f] */
h3{
	color: blue;    
} 
/* 加/deep/ 时,生成的选择器为 [data-v-3f581d8f] h3 */
/deep/ h3{
    color: blue;
}

</style>

本文主要学习 黑马程序员Vue全套视频教程,从vue2.0到vue3.0一套全覆盖,前端学习核心框架教程

如有错误,敬请指正,欢迎交流🤝,谢谢♪(・ω・)ノ