1.require.context()
1.场景:如页面需要导入多个组件,原始写法:
import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components:{titleCom,bannerCom,cellCom}
2.这样就写了大量重复的代码,利用 require.context 可以写成
const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
1. modules = {}
files.keys().forEach(key => {
const name = path.basename(key, '.vue')
modules[name] = files(key).default || files(key)
})
components:modules
这样不管页面引入多少组件,都可以使用这个方法
3.API 方法
实际上是 webpack 的方法,vue 工程一般基于 webpack,所以可以使用
require.context(directory,useSubdirectories,regExp)
接收三个参数:
directory:说明需要检索的目录
useSubdirectories:是否检索子目录
regExp: 匹配文件的正则表达式,一般是文件名
2.watch
2.1 常用用法
1.场景:表格初始进来需要调查询接口 getList(),然后input 改变会重新查询
created(){
this.getList()
},
watch: {
inpVal(){
this.getList()
}
2.2 立即执行
2.可以直接利用 watch 的immediate和handler属性简写
watch: {
inpVal:{
handler: 'getList',
immediate: true
}
}
2.3 深度监听
3.watch 的 deep 属性,深度监听,也就是监听复杂数据类型
watch:{
inpValObj:{
handler(newVal,oldVal){
console.log(newVal)
console.log(oldVal)
},
deep:true
}
}
此时发现oldVal和 newVal 值一样;
因为它们索引同一个对象/数组,Vue 不会保留修改之前值的副本;
所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面那个属性的变化
3.组件通讯
3.1 props
这个应该非常属性,就是父传子的属性;
props 值可以是一个数组或对象;
props:[]
props:{
inpVal:{
type:Number,
required: true,
default:200,
validator:(value) {
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
3.2 $emit
这个也应该非常常见,触发子组件触发父组件给自己绑定的事件,其实就是子传父的方法
<home @title="title">
this.$emit('title',[{title:'这是title'}])
3.3 vuex
1.这个也是很常用的,vuex 是一个状态管理器
2.是一个独立的插件,适合数据共享多的项目里面,因为如果只是简单的通讯,使用起来会比较重
3.API
state:定义存贮数据的仓库 ,可通过this.$store.state 或mapState访问
getter:获取 store 值,可认为是 store 的计算属性,可通过this.$store.getter 或
mapGetters访问
mutation:同步改变 store 值,为什么会设计成同步,因为mutation是直接改变 store 值,
vue 对操作进行了记录,如果是异步无法追踪改变.可通过mapMutations调用
action:异步调用函数执行mutation,进而改变 store 值,可通过 this.$dispatch或mapActions
访问
modules:模块,如果状态过多,可以拆分成模块,最后在入口通过...解构引入
3.4 attr和listeners
1.场景如果父传子有很多值那么在子组件需要定义多个解决attrs获取子传父中未在 props 定义的值
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
mounted() {
console.log(this.$attrs)
},
相对应的如果子组件定义了 props,打印的值就是剔除定义的属性
props: {
width: {
type: String,
default: ''
}
},
mounted() {
console.log(this.$attrs)
},
2.场景子组件需要调用父组件的方法解决父组件的方法可以通过listeners" 传入内部组件——在创建更高层次的组件时非常有用
<home @change="change"/>
mounted() {
console.log(this.$listeners)
}
如果是孙组件要访问父组件的属性和调用方法,直接一级一级传下去就可以
3.inheritAttrs
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
mounted() {
console.log(this.$attrs)
},
inheritAttrs默认值为true,true的意思是将父组件中除了props外的属性添加到子组件的根节点上(说明,即使设置为true,子组件仍然可以通过$attr获取到props意外的属性)
将inheritAttrs:false后,属性就不会显示在根节点上了
3.5 parent和 children
父实例children:子实例
mounted(){
console.log(this.$children)
}
mounted(){
console.log(this.$parent)
}
和parent 并不保证顺序,也不是响应式的
只能拿到一级父组件和子组件
3.6 $refs
<home ref="home"/>
mounted(){
console.log(this.$refs.home)
}
3.7 $root
mounted(){
console.log(this.$root)
console.log(this.$root.$children[0])
console.log(this.$root.$children[0].$children[0])
}
3.8 v-slot
作用就是将父组件的 template 传入子组件
插槽分类:
A.匿名插槽(也叫默认插槽): 没有命名,有且只有一个;
<todo-list>
<template v-slot:default>
任意内容
<p>我是匿名插槽 </p>
</template>
</todo-list>
<slot>我是默认值</slot>
B.具名插槽: 相对匿名插槽组件slot标签带name命名的;
<todo-list>
<template v-slot:todo>
任意内容
<p>我是匿名插槽 </p>
</template>
</todo-list>
<slot name="todo">我是默认值</slot>
C.作用域插槽: 子组件内数据可以被父页面拿到(解决了数据只能从父页面传递给子组件)
<todo-list>
<template v-slot:todo="slotProps" >
{{slotProps.user.firstName}}
</template>
</todo-list>
<slot name="todo" :user="user" :test="test">
{{ user.lastName }}
</slot>
data() {
return {
user:{
lastName:"Zhang",
firstName:"yue"
},
test:[1,2,3,4]
}
},
3.9 EventBus
1.就是声明一个全局Vue实例变量 EventBus , 把所有的通信数据,事件监听都存储到这个变量上;
2.类似于 Vuex。但这种方式只适用于极小的项目
3.原理就是利用和emit 并实例化一个全局 vue 实现数据共享
Vue.prototype.$eventBus=new Vue()
this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值')
this.$eventBus.$on("eventTarget",v=>{
console.log('eventTarget',v);
})
4.可以实现平级,嵌套组件传值,但是对应的事件名eventTarget必须是全局唯一的
3.10 路由传参
1.方案一
{
path: '/describe/:id',
name: 'Describe',
component: Describe
}
this.$router.push({
path: `/describe/${id}`,
})
this.$route.params.id
2.方案二
{
path: '/describe',
name: 'Describe',
omponent: Describe
}
this.$router.push({
name: 'Describe',
params: {
id: id
}
})
this.$route.params.id
3.方案三
{
path: '/describe',
name: 'Describe',
component: Describe
}
this.$router.push({
path: '/describe',
query: {
id: id
`}
)
this.$route.query.id
4.三种方案对比
方案二参数不会拼接在路由后面,页面刷新参数会丢失
方案一和三参数拼接在后面,丑,而且暴露了信息
3.11 Vue.observable
用法:让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象;
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新;
也可以作为最小化的跨组件状态存储器,用于简单的场景。
通讯原理实质上是利用Vue.observable实现一个简易的 vuex
import Vue from 'vue'
export const store = Vue.observable({ count: 0 })
export const mutations = {
setCount (count) {
store.count = count
}
}
<template>
<div>
<label for="bookNum">数 量</label>
<button @click="setCount(count+1)">+</button>
<span>{{count}}</span>
<button @click="setCount(count-1)">-</button>
</div>
</template>
<script>
import { store, mutations } from '../store/store'
export default {
name: 'Add',
computed: {
count () {
return store.count
}
},
methods: {
setCount: mutations.setCount
}
}
</script>