工程化开发&脚手架Vue CLI
VueCLI是Vue官方提供的一个全局命令工具。
可以帮助我们快速创建-建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
好处:
开箱即用,零配置
内置Babel等工具
标准化
安装
全局安装:cmd内输入 yarn global add @vue/cli 或 npm i @vue/cli -g
查看Vue版本:输入 vue--version
创建
在目录下右键选择 通过code打开 或者 在终端中打开
输入 vue create projectName(项目名-不能用中文)
上下键选择 vue2 或 vue3,目前先选vue2
启动
目录下cmd 或者 在vscode打开目录后终端 输入 yarnserve 或 npm run servee (具体是不是 serve 找package.json 中的 scripts)
目录文件介绍
- index.html
-
main.js
文件核心作用:导入App.vue,基于app.vue创建结构渲染index.html
-
App.vue
渲染
文件组成的三部分(文件要高亮显示需要插件Vetur)
- image-20240124001726421.png
template:结构(有且只能一个根元素)
-
script:js逻辑
导出的时当前组件的配置项
里面可以提供data(特殊) methods computed watch 生命周期八大钩子
-
style:样式(可支持less,需要装包)
-
支持less方法:style标签,lang="less"开启less功能
装包: yarn add less less-loader -D
-
普通组件的注册
-
局部注册:只能在注册的组件内使用
在app.vue中
创建 .vue 文件 (单文件组件)
在使用的组件内导入并注册
<script> //导入需要注册的组件 import 组件对象 from '.vue文件路径' export default { //局部注册 components:{ 组件名':组件对象, } } </script>
使用
当成 html 标签使用 <组件名></组件名>
组件名规范→大驼峰命名法,如:HmHeader
<template> <div class="app"> <组件名></组件名> </div> </template>
-
全局注册:所有组件内都可以使用
创建.vue文件 ,在.vue中写组件
main.js文件中进行全局注册
//导入需要全局注册的组件 import 组件名 from './components/HmButton' //调用Vue.component 进行全局注册 //Vue.component‘组件名‘,组件对象) Vue.component('HmButton', HmButton)
使用
当成 html 标签使用 <组件名></组件名>
组件名规范→大驼峰命名法,如:HmHeader
<template> <div class="app"> <组件名></组件名> </div> </template>
组件的样式冲突
默认情况:写在组件中的样式会全局生效→因此很容易造成多个组件之间的样式冲突问题。
全局样式:默认组件中的样式会作用到全局
-
局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件
组件应该有着自己独立的样式,推荐加上scoped
// 组件的vue文件内 <style scoped> div{ } </style>
scoped原理:
- 当前组件内标签都被添加data-V-hash值的属性
- css选择器都被添加[data-v-hash值]的属性选择器最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到
data函数
在组件中不再写成对象。
一个组件的 data 选项必须是一个函数。→ 保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会新执行一次 data 函数,得到一个新对象。
data(){
return{
count:100
` }
}
组件通信
组件通信,就是指组件与组件之间的数据传递
组件的数据是独立的,无法直接访问其他组件的数据
通信用属性传递消息
组件关系:
-
父子关系
-
父组件通过props将数据传递给子组件
- 父中给子添加属性传值
- 子props 接收
- 使用
// 父组件中 <template> <div> <!--1.给组件标签,添加属性的方式,传值--> <Son :title="myTitle"></Son> </div> </template> // 子组件中 <template> <div> <!--3.模板中直接使用--> {{ title }} </div> </template> <script> export default { // 2。子组件内部通过props接收 props:['title'] } </script>
-
Prop 定义:组件上注册的一些自定义属性
Prop作用:向子组件传递数据
特点:可以传递任意数量的prop
可以传递任意类型的prop
-
props校验
// 类型校验 props:{ 校验的属性名:类型// Number String Boolean Function... } // 完整校验 props:{ 校验的属性名:{ type: 类型, // Number String Boolean Function... required:true,// 是否必填 default:默认值,//设置默认值 validator (value) { //自定义校验逻辑 参数为传过来的值 return true/false } } }
-
prop & data、单向数据流
data 的数据是自己的 →随便改
prop 的数据是外部的→不能直接改,要遵循 单向数据流(单向数据流:父级 prop 的数据更新,会向下流动,影响子组件。这个数据流动是单向的。)
所以props传过来的数据要修改,需要用函数子传父信息,让父修改,通过单项数据流修改父传过来的数据
-
-
子组件利用$emit通知父组件,修改更新
- 子$emit发送消息
- 父中给子添加消息监听
- 父中实现处理函数
// 父组件中
<template>
<div>
<!--2.父组件,对消息进行监听-->
<Son :title="myTitle" @changeTitle="handleChange"></Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
exort defaule{
data(){
return {
myTitle:''
}
},
methods:{
// 3。提供处理函数,提供逻辑
handleChange (newTitle){
this.myTitle = newTitle
}
}
}
</script>
// 子组件中
<script>
export default {
methods:{
changeFn(){
// 1.通过$emit,向父组件发送消息通知
this.$emit('changeTitle',‘传智教育')
}
}
}
</script>
- 非父子关系
Vuex
-
event bus
事件总线
作用:非父子组件之间,进行简易消息传递。 (复杂场景→Vuex)
-
创建 src/utils/EventBus.js(创建一个都能访问到的事件总线 [空的 vue 实例])
import Vue from'vue' const Bus = new Vue() export default Bus
-
-
A组件(接收方),监听 Bus 实例的事件
<script> import Bus from '../utils/EventBus' export default{ created(){ Bus.$on('sendMsg', (msg) => { this.msg = msg }) } } </script>
-
B组件(发送方)(可多个),触发 Bus 实例的事件
<script> import Bus from '../utils/EventBus' export default{ methods:{ clickSend(){ //3.B组件(发送方))F触发事件的方式传递参数文(发布消息) Bus.$emit('sendMsg',‘这是一个消息') } } } </script>
-
provide&inject
跨层级共享数据。
-
父组件 provide 提供数据
<script> export default { provide () { return { //普通类型【非响应式】 color: this.color, //复杂类型【响应式】 userInfo: this.userInfo, } } } </script>
-
-
子/孙组件 inject 取值使用
<script> export default { inject: ['color','userInfo'], created () { console.log(this.color, this.userInfo) } } </script>
补充:v-model详解
原理:V-model本质上是一个语法糖。例如应用在输入框就是value属性和input事件的合写。
作用:提供数据的双向绑定
① 数据变,视图跟着变:value
② 视图变,数据跟着变 @input
注意:$event用于在模板中,获取事件的形参
<template>
<div id="app" >
<input v-model="msg" type="text">
// 等同
<input :value="msg" @input="msg = $event.target.value" type="text">
</div>
</template>
表单类组件封装 & v-model简化代码
- 表单类组件封装
因为v-model是双向绑定数据,所以会出现子组件修改父组件数据的情况,所以子组件不能写v-model 要拆开写
① 父传子:数据 应该是父组件(数据由父组件提供,方便提交) props 传递过来的,v-model 拆解 绑定数据
②子传父:监听输入,子传父传值给父组件修改
// 父组件
<BaseSelect :cityId="selectId" @事件名="selecteId =$event"/>
// 子组件
<select :value="cityId" @change="handlechange">...</select>
props: {
cityId: String
},
methods: {
handleChange (e) {
this.$emit('事件名',e.target.value)
}
}
-
v-model简化代码
因为v-model是value和input事件的合写
<BaseSelect v-model="selectId"></BaseSelect> // 等同于 <BaseSelect :value="selectId" @input="selecteId=$event"></BaseSelect>
①子组件中:props 通过value 接收,事件触发 input
②父组件中:V-model给组件直接绑数据( :value + @input )
// 子组件
<select :value="value" @change="handlechange">...</select>
props:{
value: String
},methods: {
handleChange (e) {
this.$emit('input', e.target.value)
}
}
// 父组件
<BaseSelect v-model="selectId"></BaseSelect>
.sync修饰符
作用:可以实现子组件与父组件数据的双向绑定,简化代码
特点:prop属性名可以自定义,非固定为value
本质:属性名 和 @update:属性名 合写
<BaseDialog :visible.sync="isShow" />
// 等同于
<BaseDialog :visible="isShow" @update:visible="isShow = $event"/>
// 父组件
<BaseDialog :visible.sync="isShow" />
// 子组件
props: {
visible: Boolean
}
this.$emit('update:visible', false)
ref 和 $refs
用于获取dom元素,或组件实例
-
获取dom
-
目标标签添加 ref属性
<div ref="chartRef">我是渲染图表的容器</div>
-
恰当事件,通过 this.$refs.xxx 获取目标标签
mounted () { console.log(this.$refs.chartRef) }
-
-
获取组件实例
-
目标组件添加ref属性
<BaseForm ref="baseForm"></BaseForm>
-
适当时机,通过this.$refs.xxx,获取目标组件
就可以调用组件对象里面的方法
this.$refs.baseForm.组件方法()
-
vue异步更新,$nextTick
vue是异步更新dom的,$nextTick ( 等DOM更更新后,才会触发执行此方法里的函数体 ) 可以在dom更新后做某些事
this.$nextTick(() => {
代码
})
场景:
- 点击编辑,显示编辑框
- 让编辑框,立刻获取焦点
this.isShowEdit = true // 显示输入框
this.$refs.inp.focus() // 获取焦点
Vue 是异步更新DOM(提升性能),显示之后",立刻获取焦点是不能成功的!
// 正确写法
this.isShowEdit = true
this.$nextTick(()=>{
this.$refs.inp.focus()
})