1.require.context()
父组件中导入多个组件
import titleCom from '@/components/home/titleCom'
import bannerCom from '@/components/home/bannerCom'
import cellCom from '@/components/home/cellCom'
components:{titleCom,bannerCom,cellCom}
使用require.context()
const path=require('path')
const files=require.context('@/commponent/home',false,'/\.vue$/')
const moudules={}
files.keys().from(key=>{
const name=path.basename(key,'.vue')
modules[name]=files(key).default || files(key)
})
components:modules
api描述:
/**
@params directory 需要检索的目录
@params useSubdirectories 是否检索子目录
@params regExp 匹配正则表达式,一般为文件名
*/
require.context(directory,useSubdirectories,regExp)
2.watch
2.1 常用做法
1.场景:表格初始进来的时候需要调查询接口,当input值改变的时候也需要在调用查询
created(){
this.getList()
},
watch: {
inpVal(){
this.getList()
}
}
可以这样写
watch:{
inpVal:{
handler:'getList',
immediate:true
}
}
2.watch的深度监听
watch:{
inpValObj:{
handler(newVal,oldVal){
console.log(newVal)
console.log(oldVal)
}
},
deep:true
}
注意:因为索引同一个对象/数组,vue不会保留修改之前值的副本
所以深度监听随然可以监听到对象的改变,但是无法监听到具体对象中哪个属性的变化
3. 14种组件通讯
1.props
- props :[] 不建议
- props:{}
// 对象
props:{
inpVal:{
type:String, //传入值限定类型
// type 值可为String,Number,Boolean,Array,Object,Date,Function,Symbol
// type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认
required: true, //是否必传
default:200, //默认值,对象或数组默认值必须从一个工厂函数获取如 default:()=>[]
validator:(value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
2.$emit
//父组件
<home @title="title">
//子组件
this.$emit('title',[{title:'这是title,传递给父组件的值'}])
3.vuex
state:定义存储数据的仓库,可通过this.$store.state或mapState访问
getter:获取store值,可认为是store的计算属性,可通过this.$store.getter或者mapGetters访问
mutation:同步改变store值,为什么会设计成同步,因为mutation是直接改变store值,vue对操作进行了记录,如果是异步无法追踪改变,可通过mapMutaions调用
action:异步调用函数执行mutaion,进而改变store值,可通过this.$dispatch或mapActions访问
modules:模块,如果状态过多,可以拆分成模块,最后入口通过...结构引入
例子:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
}
mutation和action的区别
- mutation 同步修改state值
- action 异步修改state值
- mutation扮演的角色:专注于修改state,理论上是修改state的唯一途径。
- action 业务代码、异步请求
理解为:如果业务种异步操作,就用action,操作state唯一的途径是mutation。
4.listeners
2.4.0新增
1.场景:如果父传子有很多值那么在子组件需要定义多个解决attrs获取子传父中未在props定义的值
// 父组件
<home title="这是标题" width="80" height="80" imgUrl="imgUrl"/>
// 子组件
mounted() {
console.log(this.$attrs) //{title: "这是标题", width: "80", height: "80", imgUrl: "imgUrl"}
},
相对应,如果子组件定义了props,打印的值就会剔除定义的属性
props:{
width:{
type:String,
default:''
}
},
mounted(){
console.log(this.$attrs)//{title: "这是标题", height: "80", imgUrl: "imgUrl"}没有width
}
2.场景子组件需要父组件的方法可以通过listeners,传入内部组件——在创建更高层次的组件时非常有用
// 父组件
<home @change="change"/>
// 子组件
mounted() {
console.log(this.$listeners) //即可拿到 change 事件
}
如果孙组件要访问父组件的属性和方法,直接一级一级传下去就好
3.inheritAttrs
//父组件
<home title="这是标题" width="80" height="80" imgUrl="imgUrl">
//子组件
mounted(){
console.log(this.$attrs)/{title: "这是标题", width: "80", height: "80", imgUrl: "imgUrl"}
}
inheritAttrs默认值为true,true的意思是将父组件中除了props外的属性添加到子组件的根节点上(说明,即使设置为true,子组件仍然可以通过$attr获取到props意外的属性)
将inheritAttrs:false后,属性就不会显示在根节点上
5.provide和inject
2.2.0新增
描述:provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。
这对选项需要一起使用
允许一个祖先组件向其所有子孙后代注入一个不依赖,不论组件层次多深,并在起上下游关系成立的时间里始终生效。
//父组件:
provide:{//provide是一个对象,提供一个属性和方法
foo:'这是foo',
fooMethod:()=>{
console.log('父组件fooMethod被调用')
}
}
//子组件
inject:['foo','fooMethod'],//数组或对象,注入到子组件
mounted(){
this.fooMethod()
console.log(this.foo)
}
//在父组件下面所有的子组件都可以利用inject
provide和inject绑定并不是响应的。
如果传入一个可监听的对象,那么其对象的属性还是响应式的,对象是因为是引用类型
//父组件
provide:{
foo:'这是foo'
},
mounted(){
this.foo='这是新的foo'
}
//子组件
inject:['foo'],
mounted(){
console.log(this.foo)//这是foo
}
6.children
父实例children:子实例
//父组件
mounted(){
console.log(this.$children)
//可以拿到一级子组件的属性和方法
//所以就可以直接改变data,或者调用methods方法
}
//子组件
mounted(){
console.log(this.$parent)//可以拿到parent的属性和方法
}
顺序不保证,也不是响应式的。
只能拿到一级父组件和子组件
7.$refs
<home ref="home"/>
mounted(){
console.log(this.$refs.home)//即可拿到子组件的实例,就可以直接操作data和methods
}
8.$root
// 父组件
mounted(){
console.log(this.$root) //获取根实例,最后所有组件都是挂载到根实例上
console.log(this.$root.$children[0]) //获取根实例的一级子组件
console.log(this.$root.$children[0].$children[0]) //获取根实例的二级子组件
}
9. .sync
在vue@1.x的时候曾作为双向绑定功能存在,即子组件可以修改父组件中的值;
在vue@2.0 由于违背单项数据流的设计被干掉了
在vue@2.3.0+以上版本又重新引入了这个.sync修饰符
//父组件
<home :title.sync="title"/>
//编译时会被拓展为
<home :title="title" @update:title="val=>title=val">
//子组件
//所有子组件可以通过$emit触发update方法改变
mounted(){
this.$emit('update:title','这是新的title')
}
例子
//父组件
<template>
<info :value="myValue" @valueChanged="e => myValue = e"></info>
</template>
<script>
inport info from './info.vue';
export default {
components: {
info,
},
data() {
return {
myValue: 1234,
}
},
}
</script>
//子组件
// info.vue组件定义了一个value 属性, 和一个valueChanged事件
<template>
<div>
<input @input="onInput" :value="value"/>
</div>
</template>
<script>
export default {
props: {
value: {
type: String
}
},
methods: {
onInput(e) {
this.$emit("valueChanged", e.target.value)
}
}
}
</script>
可以这样写
// index.vue组件 父
<info :value.sync="myValue"></info>
....
// info.vue组件 子
...
methods: {
onInput(e) {
this.$emit("update:value", e.target.value)
}
}
用法2
如果一个组件有多个prop都要实现双向绑定,根据上面学到的知识,只需要每个prop加sync修饰符
<info :a.sync="value1" :b.sync="value2" :c.sync="value2" :d.sync="value2"></info>
<info v-bind.sync="obj"></info>
<script>
..
data() {
obj: {a: '', b: '', c: '', d: ''}
}
..
</script>
10.EventBus
1.就是声明一个全局vue实例变量EventBus,把所有的通信数据,事件通监听到存储到这个变量上;
2.类似于Vuex。但这种方式只使用与极小的项目
3.原理就是利用和emit并实例化一个全局vue实现数据共享
//在main.js
Vue.prototype.$eventBus=new Vue()
//传值组件
this.$evnentBus.$emit('eventTarget','这是eventTatget传过来的值')
//接收组件
this.$eventBus.$on('eventTarget',v=>{
console.log('eventTarget',v)//这是eventTarget传来的值
})
4.可以实现平级,嵌套组件传值,但是对应的事件名eventTarget必须全局唯一的
11.路由传参
1.方案一 :会暴露在url中
//路由定义
{
path:' /describe/:id',
name:'Describe',
component:Describe
}
//页面传参
this.$router.push({
path:`/describe/${id}`,
})
//页面获取
this.$route.params.id
2.方案二 不会暴露到url中,但刷新的时候会丢失数据
//路由定义
{
path:'/describe',
name:'Describe',
component:Describe
}
//页面传参
this.$router.push({
name:'Describe',
params:{
id:id
}
})
//页面获取
this.$route.params.id
3.方案三:会拼接在url中
//路由定义
{
path:'/describe',
name:'Describe',
component:Describe
}
//页面传参
this.$router.push({
path:'/describe',
query:{
id:id
}
})
//页面获取
this.$router.query.id
12.Vue.observalbe
2.6.0新增
用法:让一个对象可响应。Vue内部就会用它来处理data函数返回的对象
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新;也可以作为最小化的跨组件状态存储器,用于简单的场景
通讯原理实质上是利用Vue.observable实现一个简易的vuex
sotre.js
import Vue from 'vue'
export const store=Vue.observable({count:0})
export const mutations={
setCount(count){
store.count=count
}
}
// vue中使用
<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 '../sotre/sotre' vue2.6新增的observable
export default {
name:'Add',
computed:{
count(){
return store.count
}
},
methods:{
setCount:mutations.setCount
}
},
</script>
13.render函数
1.场景:有些代码在template里面写会重复很多,所以这个时间render函数就有作用了
/ 根据 props 生成标签
// 初级
<template>
<div>
<div v-if="level === 1"> <slot></slot> </div>
<p v-else-if="level === 2"> <slot></slot> </p>
<h1 v-else-if="level === 3"> <slot></slot> </h1>
<h2 v-else-if="level === 4"> <slot></slot> </h2>
<strong v-else-if="level === 5"> <slot></slot> </stong>
<textarea v-else-if="level === 6"> <slot></slot> </textarea>
</div>
</template>
// 优化版,利用 render 函数减小了代码重复率
<template>
<div>
<child :level="level">Hello world!</child>
</div>
</template>
<script>
import Vue from 'vue'
Vue.component('child',{
render(createElement){
const tag=['div','p','strong','h1','h2','textarea'][this.level-1]
return createElement(tag,this.$slots.default)
},
props:{
level:{type:Number,required:true}
}
})
export defatult{
name:'zmq',
data(){return {level;3}}
}
</script>
2.render和template对比
render适合复杂逻辑,template适合简单逻辑
render属于自定render函数,template 属于声明是渲染
render性能告,template性能低
注意
注意vue组件中的定时器要在组件销毁的时候,清除掉
vue组件销毁的时候,会解绑所有指令以及事件监听
网友评论