目录
第一章:使用Vue脚手架
1.1 初始化脚手架
1.1.1 说明
1.1.2 具体步骤
1.1.3 项目模板结构
1.1.4 案例
1.2 有关render函数
1.3 修改默认配置
第二章:refs与props
2.1 refs
2.2 props
第三章:mixins混入
第四章:插件
第五章:scoped样式
第六章:自定义事件
6.1 使用
6.2 解绑自定义事件
6.3 一个注意点
6.4 总结
第七章:全局事件总线(GlobalEventBus)
第七章:消息订阅与发布(pubsub)
第八章:过渡与动画
1. Vue脚手架是Vue官方提供的标准化开发工具(开发平台)
2. 文档:https://cli.vuejs.org/zh/
第一步(仅第一次执行):全局安装@vue/cli
npm install -g @vue/cli
第二步:切换到要创建项目的目录,然后使用命令创建项目
vue create xxxx
第三步:启动项目
npm run serve
备注:
1. 如果出现下载缓慢,就配置 npm 淘宝镜像:
npm config set registryhttps://registry.npm.taobao.org
2. Vue 脚手架隐藏了所有webpack相关的配置,如果想查看具体的 webpack 配置,执行:
vue inspect > output.js
├── node_modules├── public│ ├── favicon.ico: 页签图标│ └── index.html: 主页面├── src│ ├── assets: 存放静态资源│ │ └── logo.png│ │── component: 存放组件│ │ └── HelloWorld.vue│ │── App.vue: 汇总所有组件│ │── main.js: 入口文件├── .gitignore: git 版本管制忽略的配置├── babel.config.js: babel 的配置文件├── package.json: 应用包配置文件├── README.md: 应用描述文件├── package-lock.json:包版本控制文件
把Vue学习笔记(2)最后面中的案例在脚手架环境执行 ,现在组件的名字不能只用一个单词,所以我把Student改成了MyStudent,把School改成MySchool
在main.js文件中,使用render函数来使用App组件,是因为引入Vue的时候引入的是残缺版的vue,即'vue.runtime.xxx.js',使用template标签会报错,比如说按照下面的方式来使用App组件,控制台报错
new Vue({
el: '#app',
template: ` `,
components:{
App
}
})
当创建项目之后,默认的main.js文件就是下面这个样子
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
总结:
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函数去指定具体内容
如果想要修改默认的入口文件,或者其它一些webpack设置的默认配置,可以在vue.config.js来修改,下面这个案例设置了修改入口文件,并且将保存就检查错误关闭
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
pages: {
index: {
// 入口
entry: 'src/peiqi.js',
}
},
})
这样子修改main.js名字为peiqi.js也可以执行了,其他的一些配置可以去官网上查看
当给标签添加了ref属性后,在这个组件的实例对象上就有了refs属性,这里面保存了设置ref属性的DOM元素
如下面这个案例,分别给h1标签、button按钮、school子组件分别设置ref标签,点击按钮后输出
{{msg}}
总结:
1. ref是被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取真实DOM元素,应用在组件标签上是组件实例对象
3. 使用方式:
打标识:
获取:this.$refs.xxx
功能:让组件接收外部传过来的数据
1)传递数据:
2)接收数据:
第一种方式(只接收):
props:[ 'name' ]
第二种方式(限制类型):
props:{
name: Number
}
第三种方式(限制类型、限制必要性、指定默认值):
props:{
name:{
type:String,// 类型
required:true,// 必要性
default:'老王' // 默认值
}
}
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需要确实需要修改,那就复制props的内容到data中一份,然后去修改data中的数据
在下面这个案例中,Student组件接收name、sex和age属性,模拟业务需求要修改age,设置一个button按钮,点击让年龄++,在data中用myAge接收传过来的age,在结构中使用myAge属性
{{msg}}
学生姓名:{{name}}
学生性别:{{sex}}
学生年龄:{{myAge + 1}}
功能:可以把多个组件公用的配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){......},
methods:{......}
......
}
第二部使用混入,例如:
1)全局混入:Vue.mixin(xxx)
2)局部混入:mixins: [ 'xxx' ]
下面分别是Student和School组件
{{msg}}
学生姓名:{{name}}
学生性别:{{age}}
学校名称:{{ name }}
学校地址:{{ address }}
下面这个是共用的配置mixin.js
export const hunru = {
methods:{
showName(){
alert(this.name)
}
},
mounted() {
console.log('hunru里面的mounted');
},
}
export const hunru2 = {
data(){
return{
age: 20
}
}
}
在这个共用的配置中,定义了showName函数,这样子导入hunru的组件都有了这个方法,定义mounted钩子,如果组件中也有钩子,此时先执行hunru的钩子,再执行组件中定义的钩子,如果定义了age属性,与组件中的age属性发生冲突,此时以组件中的为主,会覆盖掉hunru2里面的属性
如果定义了全局的混入,这样子所有的组件都有了混入里面定义的东西,不管是root还是App都是如此
比如说下面这个案例,定义了全局的混入里面的data有x和y,这样子Root、App、MySchool和MyStudent都有了x和y
Vue.mixin({
data(){
return{
x: 100,
y: 200
}
}
})
功能:用于增强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()
下面这个案例,在src文件夹下创建一个plugins.js文件,作为一个插件,里面添加了全局的过滤器、全局指令、全局混入以及实例方法,这样子Vue可以直接使用里面定义的东西,在install函数中,第一个参数是Vue,后面的参数就是在导入了这个插件后可以传入的参数
export default {
install(Vue, x, y, z) {
console.log(Vue, x, y, z)
// 全局过滤器
Vue.filter('mySlice', function (value) {
return value.slice(0, 4)
})
// 定义全局指令
Vue.directive('fbind', {
// 指令与元素成功绑定时
bind(element, binding) {
element.value = binding.value
},
// 指令所在的元素被插入页面时
inserted(element) {
element.focus()
},
// 指令所在的模板被重新解析时
update(element, binding) {
element.value = binding.value
},
})
// 定义混入
Vue.mixin({
data(){
return{
age: 20
}
}
})
// 给原型上添加方法(Vue实例对象和组件实例对象就可以用了)
Vue.prototype.hello = () => {
alert('hello')
}
}
}
import install from './plugins'
Vue.use(install, 1, 2, 3)
在main.js中使用这个插件,并且传入参数,在控制台输出
作用:让样式在局部生效,防止冲突
写法:
因为不同的组件中使用了相同的类名并且定义了样式,此时使用的时候可能会有冲突,加上了scoped之后,会在这个组件的标签里面添加一个属性,然后组件的样式就会添加一个属性选择器,比如说demo这个类,在添加了scoped就变成了 .demo[data-v-22321ebb],例如下面这个案例,不添加scoped,最重添加demo类的背景颜色就会取决于app组件中先导入了哪个组件,后面的样式会覆盖前面的
给两个组件的style都加上scoped,此时就不会有冲突了,并且选择器后面都会添加上一个属性选择器
要实现子给父传递数据,有两种方式,一种是通过传递函数类型的prop实现,比如下面的案例,给School传送了getSchoolName的函数,在School组件中,通过点击事件触发传过来的函数,然后把它的name属性传递给父组件,实现了子给父传递数据;另一种是通过自定义事件,先在App组件里面定义一个getStudentName的函数,在Student的标签里面定义自定义事件,模板是 v-on:xxx="xxx" ,第一个xxxx是自定义的,第二个xxx是在自己组件定义的函数,然后在Student组件中,给按钮绑定点击事件,当点击了之后,触发sendStudentName函数,函数体是 “this.$emit('get', this.name)”,这里的get就是自定义的事件,是在App组件中定义的,通过组件实例对象的$emit触发get事件,后面是它的参数
// App.vue
// School.vue
学校名称:{{ name }}
学校地址:{{ address }}
// Student.vue
{{msg}}
学生姓名:{{name}}
学生性别:{{age}}
自定义事件的v-on可以简写成@,除了这种方式外还有ref实现的,给Student加上ref属性,在mounted钩子中可以通过$refs获取这个对象然后通过$on的方式定义自定义函数‘get’,后面是当组件实例对象触发了get函数之后在App组件中调用的函数,通过这种方式会更加灵活,比如说可以绑定异步事件,定义5秒钟之后再绑定这个自定义事件......
...
...
...
mounted(){
this.$refs.student.$on('get', this.getStudentName)
}
除此之外,还有一个API可以让自定义事件只触发一次,就是once
// 这是第一种写法
// 这是第二种写法
this.$refs.student.$once('get', this.getStudentName)
通过$off()解绑自定义事件,复用上面的Student组件,创建一个button按钮,点击后解绑get自定义事件
{{msg}}
学生姓名:{{name}}
学生性别:{{age}}
如果要解绑多个自定义事件,传入要解绑的自定义事件的数组,如 this.$off(['xxx', 'yyy', 'zzz'])
如果要解绑所有的自定义事件,此时只要不传入参数即可,即 this.$off()
如果想要给一个组件绑定点击事件,本来的话应该写成
但是这样写的话会认为‘click’是自定义事件的名称,如果想要给Student绑定点击事件,就在点击事件后面加上'.native',即
组件的自定义事件
1. 一种组件间通信的方式,适用于:子组件 ==> 父组件
2. 使用场景:A是父组件,B是子组件,那么B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)
3. 绑定自定义事件
1)第一种方式,在父组件中:
或 2)第二种方式,在父组件中:
......
mounted(){
this.$refs.demo.$on('xxx', this.test)
}
3)如果想让自定义事件只能触发一次,可以使用once修饰符,或$once方法
4. 触发自定义事件:this.$emit('xxx',数据)
5. 解绑自定义事件:this.$off('xxx')
6. 组件上也可以绑定元素DOM事件,需要使用 native 修饰符
7. 注意:通过 this.$refs.xxx.$on('xxx', 回调) 绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this的指向会出问题!
1. 一种组件间通信的方式,适用于任意组件间的通信
2. 安装全局事件总线:
new Vue({
......
beforeCreate(){
Vue.prototype.$bus = this // 安装全局事件总线,$bus就是当前应用的vm
}
......
})
3. 使用事件总线:
1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
methods:{
demo(data) { ...... }
}
......
mounted() {
this.$bus.$on('xxxx', this.demo)
}
2)提供数据: this.$bus.$emit('xxxx', 数据)
4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
在下面这个案例中,main.js中安装了全局事件总线,在School组件中,创建了自定义事件“hello”,接收传过来的数据,后面可以用methods中的函数或者使用箭头函数,在Student组件中,点击按钮后调用了$emit事件,传入自定义事件“hello”并且传过去参数,在School可以接受到;在School组件被销毁前,在beforeDestroy钩子中用$off解绑自定义事件
// main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this
}
}).$mount('#app')
// School.vue
学校名称:{{ name }}
学校地址:{{ address }}
// Student.vue
{{msg}}
学生姓名:{{name}}
学生性别:{{age}}
1. 一种组件间通信的方式,适用于任意组件间的通信
2. 使用步骤:
1)安装pubsub:npm i pubsub-js
2)引入:import pubsub from 'pubsub-js'
3)接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
methods:{
demo(data) { ...... }
}
......
mounted() {
this.pid = pubsub.subscribe('xxx', this.demo) // 订阅消息
}
4)提供数据:pubsub.publish('xxx', 数据)
5)最好在beforeDestroy钩子中,用 pubsub.unsubscribe(pid)去取消订阅
在下面这个案例中,从Student组件向School传递数据, School组件通过pubsub.subscribe()的方式订阅消息‘hello’,后面的回调函数要么定义在methods中,要么使用箭头函数,如果使用function的话,函数内部的this是unefined;Student组件传递数据,通过pubsub.publish()的方式发送消息‘hello’,数据跟在后面
// School.js
学校名称:{{ name }}
学校地址:{{ address }}
{{msg}}
学生姓名:{{name}}
学生性别:{{age}}
1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
2. 图示:
3. 写法:
准备好样式:
元素进入的样式:
v-enter:进入的起点
v-enter-active:进入过程中
v-enter-to:进入的终点
元素离开的样式:
v-leave:离开的起点
v-leave-active:离开过程中
v-leave-to:离开的终点
使用
包裹要过度的元素,并配置name属性:
你好啊!
备注:若有多个元素需要过度,则需要使用:
,且每个元素都要指定
key
值。
下面三段代码分别是Test、Test2、Test3,在Test1中定义了一个动画,用transition包裹一个h1标签,当它进入的时候从左往右
Test2组件中,使用css样式来定义动画,使用tranrition-group,因为内部有两个标签,它们两个是交错显示的
Test使用了第三方组件库 animation.css ,最终的动画效果如下
你好啊
你好啊
你好啊
你好啊
你好啊