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>