Vue2基础4
修改默认配置
通过vue inspect > output.js
可以查看Vue脚手架的默认配置
创建vue.config.js
可选配置项可以去官网查看
1 | module.exports = { |
ref属性
1 | <template> |
被用来给元素或子组件注册引用信息(id的替代者)
应用在html标签上获取的是真实DOM元素
应用在组件标签上是组件实例对象(vc)
props配置项
父组件想给子组件传数据,即可通过props配置项来实现
Student.vue
1 | <template> |
使用该组件
1 | <School name='zs' age=18 sex='男'/> |
我们来观察一下props接收到的数据放在了哪里
可以看到,使用props接收到的数据都被放在了vc对象上
我们还发现_data
中并没有这些数据
props接收的数据不可修改
1 | <button @click="updateAge">尝试修改收到的年龄</button> |
1 | methods: { |
如果一定想修改,则需要使用data配置一下数据做个中转
并且展示的时候也使用data中中转的那个变量
1 | <h2>学生年龄:{{myAge}}</h2> |
1 | data(){ |
接收的同时对数据进行类型限制
如果要对类型做限制,需要通过以下写法
1 | props:{ |
传入数据
1 | <Student name="芝麻" :age="19" sex="男"/> |
如果是这样传入的
1 | <Student name="芝麻" age="19" sex="男"/> |
接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
1 | props:{ |
mixin混入
就是子组件可以共享mixin中配置的配置项
达到全局共享的效果,达到复用的目的,减少代码重复性
混合文件就是我们在构造vc的时候传入的配置项
只不过单独将其拿了出来
1 | export const hooks = { |
全局混入(全局配置):Vue.mixin(xxx)
局部混入(配置项):mixin: ['aaa']
注意点:
1 | 1、钩子以外的配置项 |
插件
我们在平时生活工作中,一款好用的插件可以极大地提高我们的生产效率,在Vue中也有这样的插件
我们来定义一个插件试一试
1 | export default { |
在main.js中使用
1 | import plugins from './plugins' |
style标签
scoped属性
1 | <style scoped> |
lang属性
1 | <style scoped lang="scss"> |
Todos案例
提前声明:此案例会循序渐进地讲到很多知识点,请务必不要跳过
静态页面代码
App.vue
1 | <template> |
动态数据
现在将数据放到data中,再补充一点逻辑吧
接下来就不写style标签啦
1 | <template> |
抽离组件
App作为王者居然写了这么多结构代码,哪里有什么组件化的思想,所以我们抽离出一个个组件
Top.vue
1 | <template> |
ShowTodosContainer.vue
1 | <template> |
这里补充一个知识点
1 | 对于<input type="checkbox"> |
PageFooter.vue
1 | <template> |
实现所有功能
插入新代办
1 | insertNewTask(){ |
删除单个代办
1 | deleteSelf(id){ |
删除所有代办
1 | deleteAllTodos(){ |
勾选
1 | <input type="checkbox" style="margin-right: 10px" v-model="allHasDone" @click="chooseAll"> |
1 | chooseAll(){ |
注意点:先处理点击事件,然后数据才更新,所以要取反
更新代办
这个有点麻烦,需要再添加一个组件,使用动态样式来控制其显示
UpdateDialog.vue
1 | <template> |
这里使用的自定义事件
我在使用该组件的时候传入一个函数,然后组件内部就可以使用this.$emit('自定义事件名')
来调用该事件
1 | <UpdateDialog :showDialog="showUpdateDialog" :task="choosedTask" @closeDialog="closeDialog"/> |
这个如果这样写会产生一个问题,就是我的task确实是动态传的,但是因为我可能会取消本次更新操作
所以我不可以这样写,这样写的话,取消按钮就是一个小丑
1 | <input type="text" v-model="task.content"> |
所以就必须得先存一份传入的值是吧,所以就应该像我刚刚那么写
但是你会发现还是有问题,检查之后发现是我存储的数据是固定在第一次传入的数据,可是我什么时候改变data中的数据呢?
监视属性
我们监视一下task,当其发生了改变,将其覆盖data中的数据
1 | watch:{ |
使用v-if配合使用
1 | <UpdateDialog v-if="JSON.stringify(choosedTask)!=='{}'" |
如果使用这种方法的话,我在closeDialog中需要将choosedTask赋值为空对象
自动获取焦点
1 | <input ref="input" type="text" v-model="updatedTaskContent" @keyup.enter="updateTask"> |
如果是监视属性实现的话
需要在监视方法中加入以下逻辑
1 | task(){ |
如果是v-if实现的话
需要再挂载的时候加入以下逻辑
1 | mounted() { |
存储
在App中封装一个save函数,将其传递给子组件,在所有对数组造成更新的地方都使用this.$emit('save')
调用该函数
1 | save(){ |
自定义事件
这个是相对于js中内置事件(keyup、click等等)的存在
js内置事件是给HTML元素使用的
自定义事件是给组件用的
主要作用就是实现父子组件之间的通信
绑定事件
1 | <template> |
绑定事件的另一种方式
1 | mount(){ |
触发事件
School.vue
1 | <template> |
Student.vue
1 | <template> |
自定义事件的触发本质还是由html的原生事件触发后,我们自己决定触发哪一个自定义事件的
props实现和自定义事件实现的区别:props需要手动接收
解绑事件
1 | this.$off('getStudentName') //解绑一个自定义事件 |
组件使用js原生事件
1 | <Student ref="student" @click.native="show"/> |
组件间通信
我们发现,组件之间的通信十分地重要,我们来理一理到现在我们学会了那些组件之间通信的方法,
1 | 1.props ===》适用于父给子传递数据和函数 ===》特点:需要手动接收,并且传递地如果是数据则不能修改 |
我们发现如果两个兄弟之间想要通信
则只能将数据状态提升
将数据放到两者共同地父组件上面去
然后父组件使用上述方法向两者传递信息
如果嵌套层级比较多,则需要多次多层传递数据,会比较麻烦
难道就只能这样了吗?NO!接下来我会讲解三种强大的方法实现任意组件之间的通信
全局事件总线
全局事件总线其实十分简单,就是使用自定义事件来实现的
只不过我们事件全部绑定在vm对象上
安装全局事件总线
1 | //创建vm |
不是一定要叫
$bus
绑定事件
1 | this.$bus.$on('hello',(data)=>{ |
触发事件
1 | this.$bus.$emit('hello',this.name) |
解绑事件
在beforeDestroy
钩子中,用$off去解绑当前组件所用到的事件。
1 | beforeDestroy() { |
原理:
1、自定义事件
2、VueComponent.prototype.__proto__ === Vue.prototype
消息订阅与发布
消息发布与订阅是一种思想,具体实现有很多种,我们这里选用pubsub-js
库
1 | npm i pubsub-js |
订阅和取消订阅消息
即设置事件和回调
即需要数据的组件
1 | mounted() { |
发布消息
即发送数据的组件
1 | pubsub.publish('hello',666) |
Vuex
它是专门在Vue中实现集中式状态管理的一个插件,对Vue应用中多个组件的共享状态进行集中式的管理,也是一种任意组件间通信的方式
状态其实指的就是数据
x是所有组件都需要使用的,所以我们将x存入Vuex中
Vuex原理图
此图摘自官网
我们可以看到该图被虚线包起来的部分即Vuex的三大重要的工具,Actions
,Mutations
,State
State译为状态,我们将需要共享的数据放入其中
Actions译为行为,我们会将对于数据的前置操作放入其中,比如条件判断,发出Ajax请求等
Mutations译为加工,我们真正对于数据的修改就是在这里进行的
Vue组件和Vuex工具之间的通信,有以下API,dispatch
,commit
,mutate
,render
只有dispatch
和commit
是我们手动调用的,其他两个都是由Vuex帮我们调用的,无需我们操心
dispatch
是我们在组件内调用的,发出对数据操作的请求
commit
是我们在actions
或者Vue组件中调用的,让其对数据做出真正的改变
接下来我们直接使用案例来驱动
求和案例
效果图
我们先将这个功能实现
因为还没有到组件共享的时候,所以现在先不使用Vuex
1 | <template> |
准备
接下来我们做些使用Vuex前的准备
创建store/index.js
文件
1 | import Vuex from 'vuex' |
在main.js
中引入该文件并并在创建vm的时候传入
1 | import Vue from 'vue' |
使用
接下来我们新建一个组件ShowSum组件,该组件的功能就是用来展示Count组件中的sum,现在我们就使用Vuex来实现此功能
先将数据都交给Vuex管理
Count.vue
1 | <template> |
store/index.js
1 | import Vuex from 'vuex' |
ShowSum.vue
1 | <template> |
当我们想要拿到state中的数据的时候,需要使用$store.state.xxx
,十分麻烦,所以Vuex就为我们提供了工具mapState
1 | <template> |
拓展
1、getters
的使用
getters我们可以理解为计算属性,就是将state中的数据加工后返回给用户
1 | import Vuex from 'vuex' |
2、mapGetters
,mapActions
,mapMutations
工具
我们对于state
中的数据可以使用mapState
来将其方便地从Vuex中拿出来
对于getters
、actions
、mutations
中的方法和数据我们也有对应的工具将其从Vuex中拿出
3、模块化开发
如果数据还有分类,我们就可以使用模块化开发
store/index.js
1 | import Vue from 'vue' |
使用模块化开发要注意一个点,就是在各个文件中需要开启命名空间
采用模块化开发使用后,mapXXX
工具的使用方法就发生了改变,改变如下
1 | ...mapState('模块名',['state参数名']), |