Vue.js 前端开发基础复习串讲之 01-Vue CLI 基础
Vue CLI
Vue CLI 概述
Vue CLI 是一个官方提供的基于 Vue.js 进行快速开发的脚手架工具,用于快速搭建基于 Vue.js 的前端项目。
Vue CLI 文档:https://cli.vuejs.org/
Vue CLI 的特点:
- 内置了 webpack 打包工具,可以快速构建项目的基本结构和配置。
- 支持自定义配置,包括 webpack 配置、开发环境和生产环境配置、环境变量等。
- 支持插件机制,可以集成其他框架和库,提高开发效率。
- 支持命令行工具,可以快速生成组件、页面、路由等。
使用 Vue CLI,需要全局安装 @vue/cli。
示例:全局安装 @vue/cli
终端执行:
# 安装vue-cli
npm install @vue/cli -g
# 查看vue-cli版本信息
vue -V
示例效果:
使用 Vue CLI 创建项目
Vue CLI 引入了图形用户界面(GUI)来创建和管理项目。通过 Vue CLI GUI,可以快速创建 Vue CLI 项目,快速地为项目安装一些插件和依赖。
示例:使用 GUI 创建项目
终端执行:
# 运行GUI
vue ui示例效果:
在浏览器中打开 GUI:
在 GUI 中创建项目,手动配置项目,注意选择插件和 Vue.js 版本:
项目创建完成后,可以在 GUI 中对项目和插件进行管理:
使用 IDEA 打开创建好的 Vue 脚手架项目:
打开 package.json,执行 serve 指令,运行 Vue 脚手架项目:
示例效果:
Vue CLI 项目结构
使用 Vue CLI 创建的项目:
文件/文件夹结构:
| 名称 | 描述 |
|---|---|
| node_modules | 通过 npm 下载的项目中使用的依赖包 |
| public | 包含 index.html 文件,是项目的入口页面 该文件夹可以存放静态资源,静态资源不会被 webpack 压缩 |
| src | 包含项目的源代码 |
| src/assets | 存放静态资源,如图片、样式表等 该文件夹存放的静态资源会被 webpack 压缩 |
| src/components | 存放 Vue 普通组件 |
| src/App.vue | 所有组件的根组件 |
| src/main.js | 项目的入口 JavaScript 文件 全局的配置和初始化设置在这里执行 |
| package.json | npm 配置文件 |
| vue.config.js | Vue CLI 配置文件,可以配置 Vue CLI 选项 如 webpack 配置、开发服务器设置等 |
src/main.js:项目的入口 JavaScript 文件。
// 导入相关内容
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 实例化Vue实例
// 渲染APP实例,并挂载到index.html的#app上
new Vue({
render: h => h(App)
}).$mount('#app')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>*.vue 文件:Vue 单文件组件。每一个 Vue 组件都包含 script、template、style。
<script>
// export default对外抛出组件,方便其他位置调用
export default {
// 组件配置
}
</script>
<template>
<!-- 组件模板,有且只能有一个根标签 -->
</template>
<style scoped>
<!--
组件的CSS样式
scoped:样式只针对当前组件有效
-->
</style>package.json:npm 配置文件。
{
"name": "vuecli-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"vue-template-compiler": "^2.6.14"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}vue.config.js:Vue CLI 配置文件。配置文档:https://cli.vuejs.org/zh/config/
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: { // 配置开发环境
port: 8080, // 端口号
}
})Vue 组件的属性和方法
data()
data() 函数用于定义组件中的数据,函数内返回一个数据对象。
- 在组件模板中通过插值表达式 {{属性名 xxx}} 访问数据。
- 在 JavaScript 中可以通过 this.$data.xxx 的方式访问数据。
- Vue 实例代理了 data 对象,可以通过 this.xxx 的方式访问数据。
示例:data()
根组件(src/App.vue):
<template>
<div>
<h3>title:{{title}}</h3>
<h3>user.name:{{user.name}}</h3>
</div>
</template>
<script>
export default {
name: 'App',
data() {
// 定义组件数据,返回数据对象
return {
title: 'Hello Vue CLI!',
user: {
name: 'duozai',
age: 26
}
}
}
}
</script>示例效果:
methods
methods 属性用于定义组件中的方法。
- 定义在 methods 属性中的方法可以作为页面中的事件处理方法使用,如按钮点击事件等。
- 在定义的方法中,this 指向 Vue 实例本身。
示例:methods
根组件(src/App.vue):
<template>
<div>
<!-- ... -->
<h3>user.age:{{user.age}}</h3>
<button @click="updateAge">user.age++</button>
</div>
</template>
<script>
export default {
// ...
methods: {
updateAge() {
this.user.age++
}
}
}
</script>示例效果:
computed
computed 属性用于定义组件中的计算属性。
当有一些数据需要随着其他数据变动而变动时,可以使用 computed 计算属性。
- 计算属性结果会被缓存起来。
- 计算属性依赖的属性发生变化时,会重新计算计算属性的值。
- 在组件模板中中直接通过插值表达式 {{属性名 xxx}} 的方式显示计算属性的数据。
- 计算属性适合于简单的数据转换和同步计算。
示例:computed
根组件(src/App.vue):
<template>
<div>
<!-- ... -->
<h3>user.age:{{user.age}}</h3>
<h3>user.tag:{{userTag}}</h3>
<button @click="updateAge">user.age++</button>
</div>
</template>
<script>
export default {
// ...
computed: {
userTag() {
if(this.user.age <= 30) {
return "青年"
} else if(this.user.age <= 50) {
return "中年"
} else if(this.user.age > 50) {
return "老年"
}
}
}
}
</script>示例效果:
watch
watch 属性用于定义组件中的状态监听。
watch 状态监听可以监听当前组件中的数据变化,调用当前数据所绑定的事件处理方法。
- 状态监听是执行代码响应数据变化的,不返回值。
- 状态监听不进行缓存,每当监听的数据变化时总是会执行。
- 状态监听适合执行数据变化时的异步操作或较为复杂的数据处理。
示例:watch
根组件(src/App.vue):
<template>
<div>
<h3>count:{{count}}</h3>
<button @click="updateCount">count++</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
updateCount() {
this.count++
}
},
watch: {
count(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
</script>示例效果:
生命周期钩子函数
添加自己的代码的机会。
组件生命周期对应的钩子函数:
| 名称 | 描述 |
|---|---|
| beforeCreate | 组件创建前执行,此时无法访问组件中的数据和方法 |
| created | 组件创建后执行,此时可以访问组件中的数据和方法 一般在这个生命周期中发送异步请求 |
| beforeMount | 组件挂载成功前执行,此时组件 DOM 未编译 |
| mounted | 组件挂载成功后执行,此时组件 DOM 已编译 |
| beforeUpdate | 组件更新之前执行,此时数据是新的,页面是旧的 |
| updated | 组件更新之后执行,此时数据和页面都是新的 |
| beforeDestory | 组件销毁之前执行 |
| destoryed | 组件销毁之后执行 |
Vue 内置指令
v-model
v-model 指令用于实现双向数据绑定,常用于表单元素上。
双向数据绑定:页面中的数据改变时 data 中的数据会改变,data 中的数据改变时页面中的数据也会改变,双向数据绑定是数据驱动视图的结果。
v-model 的基本用法:
<input v-model="xxx">示例:v-model
根组件(src/App.vue):
<template>
<div>
<div>userName:<input v-model="userName"></div>
<div>userName:{{userName}}</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
userName: 'duozai'
}
}
}
</script>示例效果:
v-bind/:xxx
v-bind 指令用于实现单向数据绑定,常用于绑定 HTML 元素属性。
单向数据绑定:页面中的数据改变时 data 中的数据不会改变,data 中的数据改变时页面中数据会改变。
v-bind 的基本用法:
<div v-bind:元素属性="xxx"></div>
<div :元素属性="xxx"></div>示例:v-bind
根组件(src/App.vue):
<template>
<div>
<!-- ... -->
<div :id="userName">userName:{{userName}}</div>
</div>
</template>
<script>
export default {
// ...
}
</script>示例效果:
v-on/@xxx
v-on 指令是事件监听指令,直接与标签的事件类型(如 click、change 事件等)配合使用,可以在触发事件时运行一些 JavaScript 代码,或绑定事件处理方法。
v-on 的基本用法:
<button v-on:事件类型="xxx"></button>
<button @事件类型="xxx"></button>示例:v-on
根组件(src/App.vue):
<template>
<div>
<!-- ... -->
<button @click="btnClick">click</button>
</div>
</template>
<script>
export default {
// ...
methods: {
btnClick() {
alert('button click!')
}
}
}
</script>示例效果:
v-text 和 v-html
v-text 指令用于在元素内部插入文本内容。
v-html 指令用于在元素内部插入 HTML 标签内容。
v-text 和 v-html 的基本用法:
<p v-text="xxx"></p>
<p v-html="xxx"></p>示例:v-text 和 v-html
根组件(src/App.vue):
<template>
<div>
<!-- ... -->
<div v-text="userName"></div>
<div v-html="userName"></div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
userName: '<h3>duozai</h3>'
}
},
// ...
}
</script>示例效果:
v-for
v-for 指令用于实现页面列表渲染,常用来循环数组。
v-for 的基本用法:
<div v-for="(item, index) in list" :key="id"></div>v-for 指令的基本参数:
| 名称 | 描述 |
|---|---|
| list | 要遍历的数据列表/数组 |
| item | 遍历后的每一个元素的别名 |
| index | 当前元素的索引值 |
| key | 使用 v-for 时,需要为每项提供一个唯一的 key 属性 其主要用于 Vue 的 diff 算法,提高遍历效率 key 的值只能是字符串或数字类型,且必须具有唯一性 建议把数据项的主键 id 属性的值作为 key 的值 |
示例:v-for
根组件(src/App.vue):
<template>
<div>
<div v-for="(item, index) in userList" :key="item.id">
{{index}} => {{item.name}}
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
userList: [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' },
{ id: 4, name: '赵六' },
{ id: 5, name: '陈七' }
]
}
}
}
</script>示例效果:
v-if 和 v-show
v-if 指令用于控制元素显示隐藏,其会对元素进行删除和重新创建,性能较低。
v-show 指令用于控制元素显示隐藏,其本质是操作元素的 display 属性,不会对元素进行删除和重新创建,性能较高。
v-if 和 v-show 的基本用法:
<p v-if="条件"><p>
<p v-else></p>
<p v-show="条件"></p>示例:v-if 和 v-show
根组件(src/App.vue):
<template>
<div>
<div>
<h3 v-if="isHome">Home Page</h3>
<h3 v-if="!isHome">Login Page</h3>
</div>
<div>
<h3 v-show="isHome">Home Page</h3>
<h3 v-show="!isHome">Login Page</h3>
</div>
<button @click="isHome=!isHome">toggle</button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
isHome: true
}
}
}
</script>示例效果:
Vue 组件系统
组件注册
在 Vue CLI 中,可以将普通组件放在 src/components 文件夹下,并使用局部注册或全局注册的方式注册组件。
局部注册的组件,仅在注册它的父组件及其子组件中可用,其他未注册的组件无法直接使用。
示例:局部注册组件
MyComponent 组件(src/components/MyComponent.vue):
<template>
<div>
<h3>hello,这是MyComponent组件</h3>
</div>
</template>根组件(src/App.vue):
<script>
// 导入MyComponent组件
// import 对象名称 from 路径
// 对象名称可以自定义
import MyComponent from "@/components/MyComponent.vue"
export default {
name: 'App',
// 局部注册组件
components: {
// 组件名称: 组件对象
// 组件名称=组件对象时,可以缩写成MyComponent
MyComponent: MyComponent
}
}
</script>
<template>
<div>
<!-- 调用MyComponent组件 -->
<myComponent></myComponent>
</div>
</template>示例效果:
全局注册的组件,在整个 Vue 应用的所有组件(包括子组件、孙组件等嵌套组件)中都可以直接使用,无需再次导入或注册。
示例:全局注册组件
项目入口文件(src/main.js):
// 导入MyComponent组件
// import 对象名称 from 路径
// 对象名称可以自定义
import MyComponent from "@/components/MyComponent.vue"
// 全局注册组件
// 参数1:组件名称
// 参数2:组件对象
Vue.component('MyComponent', MyComponent)根组件(src/App.vue):
<template>
<div>
<!-- 调用MyComponent组件 -->
<myComponent></myComponent>
</div>
</template>示例效果:
组件插槽
Vue 中的组件中使用 template 模板定义 HTML 结构,为了方便使用 template 公共模板结构,Vue 提出了插槽(Slots)的概念,插槽就是定义在组件内部的 template 模板。
示例:组件插槽
根组件(src/App.vue):
<template>
<div>
<myComponent>
<!-- 调用组件时传递插槽模板 -->
<span>多仔</span>
</myComponent>
</div>
</template>MyComponent 组件(src/components/MyComponent.vue):
<template>
<div>
<!-- <slot> 相当于插槽模板的占位符 -->
<h3>hello,<slot></slot></h3>
</div>
</template>示例效果:
当调用组件时配置了多个插槽,可以为插槽命名。
示例:具名插槽
根组件(src/App.vue):
<template>
<div>
<myComponent>
<!--
每一个插槽模板都是一个<template>标签
使用v-slot指令来指定插槽名称
-->
<template v-slot:name>
<span>多仔</span>
</template>
<template v-slot:age>
<span>26</span>
</template>
</myComponent>
<myComponent>
<template v-slot:name>
<span>少仔</span>
</template>
<template v-slot:age>
<span>18</span>
</template>
</myComponent>
</div>
</template>MyComponent 组件(src/components/MyComponent.vue):
<template>
<div>
<!--
<slot> 相当于插槽模板的占位符
使用name属性指定插槽名称
-->
<h3>hello,<slot name="name"></slot></h3>
<h3>我的年龄是<slot name="age"></slot></h3>
</div>
</template>示例效果:
组件通信
组件实例内部具有自己的独立作用域,不能直接被外部访问。
组件之间的数据传递需要借助一些工具来实现,且组件之间的数据传递是单向的。
父组件向子组件传递数据的基本思想:
- 父组件中给子组件绑定属性。
- 子组件内部通过 props 选项接收数据。
示例:父组件向子组件传递数据
根组件(src/App.vue):
<template>
<div>
<!-- 以属性的方式传递数据 -->
<myComponent name="多仔" age="26"></myComponent>
<myComponent name="少仔" age="18"></myComponent>
</div>
</template>子组件(src/components/MyComponent.vue):
<script>
export default {
name: "MyComponent",
// 使用props接收数据
props: ['name', 'age'],
}
</script>
<template>
<div>
<h3>我的姓名是{{name}}</h3>
<h3>我的年龄是{{age}}</h3>
</div>
</template>示例效果:
子组件向父组件传递数据的基本思想:
- 父组件中给子组件标签通过 @ 绑定自定义事件。
- 子组件内部通过 emit 方法触发事件。
示例:子组件向父组件传递数据
子组件(src/components/MyComponent.vue):
<script>
export default {
name: "MyComponent",
data() {
return {
msg: 'Hello World'
}
},
methods: {
sendMessage() {
// 通过this.$emit触发事件,并传递参数
// 参数1:父组件调用子组件时绑定的事件名称
// 参数2:要传递的参数
this.$emit('receive', this.msg)
}
}
}
</script>
<template>
<div>
请输入消息:<input v-model="msg">
<button @click="sendMessage">发送</button>
</div>
</template>根组件(src/App.vue):
<template>
<div>
<!--
父组件在调用子组件时绑定一个自定义事件,触发接收方法
事件名称和子组件emit触发的事件名称一致
this.$emit('receive', this.msg)
-->
<myComponent @receive="receive"></myComponent>
<div>子组件传递给父组件的数据:{{msg}}</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
msg: ''
}
},
methods: {
// 接收子组件传递给父组件数据的方法
// 参数1:子组件传递给父组件的数据
receive(msg) {
// 将子组件传递的数据保存给父组件
this.msg = msg
}
}
}
</script>示例效果: