Vue工程化开发
脚手架
创建脚手架
使用步骤:
1.全局安装(一次):yarn globaladd @vue/cli 或 npm i @vue/cli -g
2.查看 Vue 版本:`vue --version
3.创建项目架子:vue create project-name(项目名-不能用中文)
4.启动项目:yarn serve 或 npm run serve( 看package.json的配置 )
官方文档网址
修改入口文件等操作,在 vue.config.js中配置
Vuecli自定义创建项目
步骤:
1、安装脚手架
2、创建项目:
vue create 项目名
3、选择自定义: Manually select features
选择特性:(根据自己的项目来,需要什么选什么,上下键选择,空格键选中)
具体选择(根据自己的项目进行选择)
ESLint代码规范
代码规范:一套写代码的约定规则。例如:"赋值符号的左右是否需要空格""一句结束是否是要加;"…
JavaScript Standard Style(目前市场上使用最多的规范): https://standardis.com/rules-zhcn.html
下面是这份规则中的一小部分:
- 字符串使用单引号 'abc'
- 无分号 const name ='zs'
- 关键字后加空格 if(name ='ls'){..}
- 函数名后加空格 function name (arg){...}
- 坚持使用全等 ===、摒弃 ==
- .....
一切不符合规范的代码都会报错
ESLint查找并修正错误
①手动修正:
根据错误提示来一项一项手动修改纠正,
如果你不认识命令行中的语法报错是什么意思,根据错误代码去[ESLint 规则表]中查找其具体含义
② 自动修正
基于 VsCode 插件 ESLint ** 高亮错误,并通过配置** 自动 帮助我们修复错误
// 当保存的时候,eslint自动帮我们修复错误"
"editor.codeActionsOnSave": {
"source.fixAll": true
},
//保存代码,不自动格式化'
"editor.formatOnSave":false,
有可能代码声明了变量没有使用等不能自动修正的代码,也会报错,此时得自己修正手动错误
非单文件组件
基本使用
Vue中使用组件的三大步骤:
一、定义组件(创建组件) const 变量名 = Vue.extend({这里面配置和new Vue差不多,但是没有el})
二、注册组件 局部注册:new Vue内配置 components 全局注册:Vue.component('组件名',组件)
三、使用组件(写组件标签) 模板内使用<组件名></组件名>
一、如何定义一个组件?
使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
区别如下:
1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。
二、如何注册组件?
1.局部注册:靠new Vue的时候传入components选项
2.全局注册:靠Vue.component('组件名',组件)
三、编写组件标签:
<div id="id" class="">
<h1>{{str}}</h1>
<!-- 使用组件 -->
<school></school>
<hr>
<students></students>
<all></all>
</div>
<div id="id2" class="">
<all></all>
</div>
<script src="../../vue.js"></script>
<script>
// 创建组件
const school = Vue.extend({
template: `
<div>
<div>学校 :{{name}}</div>
<div>地址 :{{address}}</div>
</div>`,
data() {
return {
name: '清华',
address: '北京'
}
}
})
const students = Vue.extend({
template: `
<div>
<div>学生 :{{name}}</div>
<div>年龄 :{{age}}</div>
</div>
`,
data() {
return {
name: '卡卡',
age: 20
}
}
})
const all = Vue.extend({
template: `<div><h2>全局配置</h2></div>`
})
// 全局注册
Vue.component('all', all)
new Vue({
el: '#id',
data: {
str: '非单文件组件'
},
// 局部注册组件
components: {
school,
students
}
})
new Vue({
el: '#id2'
})
</script>
注意点
1.关于组件名:
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时,
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
VueComponent(组件实例对象:vc)
关于VueComponent:
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写
即Vue帮我们执行的:new VueComponent(options)。
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
4.关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。
Vue的实例对象,以后简称vm。
单文件组件
使用
1.创建 .vue 文件 ,里面配置,一个文件就是一个组件,最终都要被App.vue管理,之后再到入口文件引入
Student组件 (子组件)
<template>
<!-- 配置模板结构 -->
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
</template>
<script>
// 默认导出
export default {
//这里面配置组件信息
name:'Student',//组件名,一般和文件名相同
data(){
return {
name:'张三',
age:18
}
};
</script>
<style>
/*样式结构*/
</style>
App.vue 统帅组件(父组件/根组件)
<template>
<div>
<Student></Student>
</div>
</template>
<script>
//引入 Student组件
import Student from "./components/Student";
export default {
//组件注册
components: {
Student
},
};
</script>
入口文件
//引入Vue 和 App组件
import Vue from 'vue'//这是个不完整的vue,只包含核心,没有模板解析器
import App from './App.vue'
new Vue({
template: `<app></app>`,
el: '#app',
render: h => h(App)//引入的vue不包含模板解析器,所以要用render
})
关于不同版本的Vue
1.vue.js与vue.runtime.xxx.js的区别:
(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。
2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
render函数接收到的createElement函数去指定具体内容。
注册全局组件
入口文件中 / main.js中
// 引入组件
import all from './components/all'
// 全局注册
Vue.component('all', all)
组件间通信
父传子
prop配置项
-
功能:让组件接收外部传过来的数据
-
传递数据:
<Demo name="xxx"/> -
接收数据:
-
第一种方式(只接收):
props:['name'] -
第二种方式(限制类型):
props:{name:String}用的最多 -
第三种方式(限制类型、限制必要性、指定默认值):
props:{ name:{ type:String, //类型 required:true, //必要性 ,是否必填 default:'老王', //默认值 validator(value){ //自定义校验逻辑 return 是否通过校验 //if (value > 100) { //return true // } else { // console.error('传入的数字必须大于100') //return false } } } }
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
-
子传父
this.$emit('事件名',数据)
自定义事件(子传父)
组件中的通信机制:子组件==>父组件 (子组件 传 数据 给 父组件)
绑定方式:
1.在组件标签中绑定:父组件中 <School @事件名=“回调函数”/> 或 <School v-on:事件名=“回调函数”/>
2.用ref绑定:父组件中
<Demo ref="标识名"/>
......
mounted(){
this.$refs.标识名.$on('事件名',回调函数)
}
3.若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。
触发自定义事件:触发事件的组件中this.$emit('事件名',参数(根据情况传入参数,可以有多个))
解绑自定义事件:触发事件的组件中
解绑单个 :this.off('事件名')
解绑多个 :this.off(['事件名1','事件名2'])
全部解绑 :this.off()
组件上也可以绑定原生DOM事件,需要使用native修饰符。
注意:通过this.$refs.标识名.$on('事件名',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
全局事件总线(GlobalEventBus)
是一种组件间的通信机制:(任意组件间的通信)
使用:
1、安装全局事件总线:在入口文件中(main.js 或 index.js)
// 法一:给Vue的一个实例对象安装全局事件总线
// Vue.prototype.$bus = new Vue()
// 法二:在当前管理组件的Vue实例对象的钩子上安装
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})
2.使用:
①哪个组件需要接收数据就在哪个组件的mounted钩子上给$bus注册事件监听
methods(){
demo(data){......}
}
......
mounted() {
//注册事件监听
this.$bus.$on('事件名',this.demo)//可直接写回调函数,建议将回调写到方法中
}
②发送数据的组件中
// 发送
this.$bus.$emit('事件名',数据)
③注册事件监听解的组件绑事件监听
beforeDestroy() {
// 解绑事件监听器
this.$bus.$off('事件名')
}
父传子孙通信-provide&inject配置项
provide&inject作用:跨层级共享数据,可以理解为后代组件共用的data,但是后代组件需要用inject接收
1.父组件 provide 提供数据
export default {
data() {
return {
color: 'blue',
userInfo: {
name: 'kaka',
age: 17,
},
}
},
provide() {
return {
// 普通类型 【非响应式】
color: this.color,
// 复杂属性 【响应式】
userInfo: this.userInfo,
}
},
}
2.子组件 inject 获取数据
export default {
inject: ['color', 'userInfo'],
}
mixin(混入/合)配置项
-
功能:可以把多个组件共用的配置提取成一个混入对象
-
使用方式:
第一步定义混合——创建一个名为xxx的js文件,在里面配置组件需要共用的部分:
export default { data(){....}, methods:{....} .... }全局也可以直接 :
Vue.mixin({这里面配置})第二步使用混入:
1.哪个组件需要使用,就引入该混合文件。
2.混入
全局混入:入口文件中配置:
Vue.mixin(xxx)
局部混入:vc中配置:mixins:['xxx']
插件
-
功能:用于增强Vue
-
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
-
定义插件:
对象.install = function (Vue, options) { // 1. 添加全局过滤器 Vue.filter(....) // 2. 添加全局指令 Vue.directive(....) // 3. 配置全局混入(合) Vue.mixin(....) // 4. 添加实例方法 Vue.prototype.$myMethod = function () {...} Vue.prototype.$myProperty = xxxx } -
使用插件:
Vue.use(插件名(文件名))
scoped样式
在组件的样式中,样式默认是混合的,容易造成类名重复,需要用 scoped来限制
- 作用:让样式在局部生效,防止冲突。
- 写法:
<style scoped>
消息订阅与发布(pubsub)
也是一种组件间通信的技术,和全局事件总线相似 (任意组件间通信)
使用步骤:
-
安装pubsub:
npm i pubsub-js -
引入:
import pubsub from 'pubsub-js'(发送数据和接收数据的组件都需要引入) -
获取数据的组件
pubsub.subscribe('订阅名',回调函数)mounted() { // this.pid = pubsub.subscribe('订阅名',回调函数) // 回调函数的第一个参数是订阅名,第二个才是数据 // 和定时器的感觉一样,会返回一个订阅id this.pid = pubsub.subscribe('getData', (pbname, data) => { console.log(data) }) }, beforeDestroy() { // 取消订阅 pubsub.unsubscribe(this.pid) }, } -
发送数据的组件:
pubsub.publish('xxx',数据)
ref获取Dom和组件实例
给标签添加的标识,相当于(id的替代)
1.配置ref属性:内置标签 : <h1 ref="xxx"></h1> 组件标签 <School ref="xxx"/>
2.获取Dom和组件实例:this.$refs.xxx 内置标签获取到的是Dom , 组件标签获取到的是组件实例对象
3 .this$refs.xxx获取到组件实例对象,可以直接.方法名()调用该组件的方法
$nextTick
基本使用
-
- 语法:
this.$nextTick(回调函数) - 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。(比如input输入框获取焦点时)
- 语法:
input自动获取焦点
<template>
<div class="app">
<input v-if="isEdit" ref="inp" type="text" />
<span v-else>点击编辑显示输入框</span>
<button @click="edit">编辑</button>
</div>
</template>
<script>
export default {
data() {
return {
isEdit: false,
}
},
methods: {
edit() {
// 让输入框显示
this.isEdit = true
// 让输入框获取焦点
// this.$refs.inp.focus()//此处报错,因为vue是异步更新DOM,此时无法获取到DOM
this.$nextTick(() => {
// this.$nextTick(回调函数),这里面的回调函数是当DOM更新完才执行
this.$refs.inp.focus()
})
},
},
}
</script>
插槽(父传子,子传父)
作用:
让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
作用域插槽:父组件 <===> 子组件
分类:
默认插槽、具名插槽、作用域插槽
使用方式:
默认插槽:
只是简单的一处需要插入内容时使用
父组件中:
<Category>
<div>html结构1</div>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot>插槽默认内容...</slot>
</div>
</template>
具名插槽:
子组件有多处不同需要插入时使用
父组件中:
<Category>
<template slot="head">//写法一
<div>html结构1</div>
</template>
<template v-slot:center>//写法二
<div>html结构2</div>
</template>
<template #footer>//写法三
<div>html结构2</div>
</template>
</Category>
子组件中:
<template>
<div>
<!-- 定义插槽 -->
<slot name="head">插槽默认内容...</slot>
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容...</slot>
</div>
</template>
作用域插槽:
父组件需要子组件的数据做操作时
基本使用步骤:
1.给 slot 标签,以添加属性的方式传值
<slot :id="item.id" msg="测试文本"></slot>
2.所有添加的属性,都会被收集到一个对象中
{id:3,msg:'测试文本'}
3.在template中,通过#插槽名="obj" 接收,默认插槽名为 default
<MyTable :list="list">
<!-- 接收数据 -->
<template #default="obj">
<button @click="del(obj.id)">删除</button>
</template>
</MyTable>
单页面应用程序
什么是单页面应用程序?
所有功能在一个html页面上实现
单页面应用优缺点?
优点:按需更新性能高,开发效率高,用户体验好缺点:学习成本,首屏加载慢,不利于SEO
应用场景?
系统类网站/内部网站/文档类网站 /移动端站点
Vue封装的过渡与动画
-
作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
-
图示:
-
写法:
-
准备好样式:
- 元素进入的样式:
- v-enter:进入的起点
- v-enter-active:进入过程中
- v-enter-to:进入的终点
- 元素离开的样式:
- v-leave:离开的起点
- v-leave-active:离开过程中
- v-leave-to:离开的终点
- 元素进入的样式:
-
使用
<transition>包裹要过度的元素,并配置name属性:<transition name="hello"> <h1 v-show="isShow">你好啊!</h1> </transition> -
备注:若有多个元素需要过度,则需要使用:
<transition-group>,且每个元素都要指定key值。
-