Site Overlay

Vue不得不说的细节

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$/)
const 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.listeners 跟 attrs(这两个是不常用属性,但是高级用法很常见)

 


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"}
},
listeners" 传入内部组件——在创建更高层次的组件时非常有用
// 父组件
<home @change="change"/>

// 子组件
mounted() {
console.log(this.$listeners) //即可拿到 change 事件
}

3.provide和inject

描述: 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'
}

4.EventBus

1.就是声明一个全局Vue实例变量 EventBus , 把所有的通信数据,事件监听都存储到这个变量上;

2.类似于 Vuex。但这种方式只适用于极小的项目

3.原理就是利用

emit 并实例化一个全局 vue 实现数据共享
// 在 main.js
Vue.prototype.$eventBus=new Vue()

// 传值组件
this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值')

// 接收组件
this.$eventBus.$on("eventTarget",v=>{
console.log('eventTarget',v);//这是eventTarget传过来的值
})

5.render 函数

场景:有些代码在 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 type='text/javascript'>
import Vue from 'vue'
Vue.component('child', {
render(h) {
const tag = ['div', 'p', 'strong', 'h1', 'h2', 'textarea'][this.level]
return h(tag, this.$slots.default)
},
props: {
level: { type: Number, required: true }
}
})
export default {
name: 'hehe',
data() { return { level: 3 } }
}
</script>

render 和 template 的对比 前者适合复杂逻辑,后者适合逻辑简单; 后者属于声明是渲染,前者属于自定Render函数; 前者的性能较高,后者性能较低。

6.动态组件

场景:做一个 tab 切换时就会涉及到组件动态加载

<component v-bind:is="currentTabComponent"></component>

但是这样每次组件都会重新加载,会消耗大量性能,所以 就起到了作用

<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>

这样切换效果没有动画效果,这个也不用着急,可以利用内置的

<transition>
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
</transition>

7.递归组件

场景:如果开发一个 tree 组件,里面层级是根据后台数据决定的,这个时候就需要用到动态组件
// 递归组件: 组件在它的模板内可以递归的调用自己,只要给组件设置name组件就可以了。
// 设置那么House在组件模板内就可以递归使用了,不过需要注意的是,
// 必须给一个条件来限制数量,否则会抛出错误: max stack size exceeded
// 组件递归用来开发一些具体有未知层级关系的独立组件。比如:
// 联级选择器和树形控件

<template>
<div v-for="(item,index) in treeArr">
子组件,当前层级值: {{index}} <br/>
<!-- 递归调用自身, 后台判断是否不存在该值 -->
<tree :item="item.arr" v-if="item.flag"></tree>
</div>
</template>
<script>
export default {
// 必须定义name,组件内部才能递归调用
name: 'tree',
data(){
return {}
},
// 接收外部传入的值
props: {
item: {
type:Array,
default: ()=>[]
}
}
}
</script>

//ps:递归组件必须设置name 和结束的阀值

8.mixins

场景:有些组件有些重复的 js 逻辑,如校验手机验证码,解析时间等,mixins 就可以实现这种混入 mixins 值是一个数组

const mixin={
created(){
this.dealTime()
},
methods:{
dealTime(){
console.log('这是mixin的dealTime里面的方法');
}
}
}

export default{
mixins:[mixin]
}

9.Vue.nextTick

场景:页面加载时需要让文本框获取焦点 用法:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

mounted(){ //因为 mounted 阶段 dom 并未渲染完毕,所以需要$nextTick
this.$nextTick(() => {
this.$refs.inputs.focus() //通过 $refs 获取dom 并绑定 focus 方法
})
}

10.Vue.directive

场景:官方给我们提供了很多指令,但是我们如果想将文字变成指定的颜色定义成指令使用,这个时候就需要用到Vue.directive

// 全局定义
Vue.directive("change-color",function(el,binding,vnode){
el.style["color"]= binding.value;
})

// 使用
<template>
<div v-change-color>{{message}}
</div>
</template>
<script>
export default{
data(){
return{
color:'green'
}
}
}
</script>

11.Vue.config.keyCodes

场景:自定义按键修饰符别名
// 将键码为 113 定义为 f2

Vue.config.keyCodes.f2 = 113;
<input type="text" @keyup.f2="add"/>

12.v-pre

场景:vue 是响应式系统,但是有些静态的标签不需要多次编译,这样可以节省性能

<span v-pre>{{ this will not be compiled }}</span>   
// 显示的是{{ this will not be compiled }}

<span v-pre>{{msg}}</span>
// 即使data里面定义了msg这里仍然是显示的{{msg}}

13.v-cloak

场景:在网速慢的情况下,在使用vue绑定数据的时候,渲染页面时会出现变量闪烁 用法:这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕

// template 中
<div class="#app" v-cloak>
<p>{{value.name}}</p>
</div>

// css 中
[v-cloak] {
display: none;
}
//这样就可以解决闪烁,但是会出现白屏,这样可以结合骨架屏使用

14.v-once

场景:有些 template 中的静态 dom 没有改变,这时就只需要渲染一次,可以降低性能开销

<span v-once> 这时只需要加载一次的标签</span>
//v-once 和 v-pre 的区别: v-once只渲染一次;v-pre不编译,原样输出

15.事件修饰符

.stop:阻止冒泡
.prevent:阻止默认行为
.self:仅绑定元素自身触发
.once: 2.1.4 新增,只触发一次
.passive: 2.3.0 新增,滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用

16.按键修饰符和按键码

场景:有的时候需要监听键盘的行为,如按下 enter 去查询接口等
// 对应键盘上的关键字
.enter (回车键)
.tab (制表键)
.delete (捕获“删除”和“退格”键)
.esc (退出键)
.space (空格键)
.up ( ↑ 键)
.down ( ↓ 键)
.left ( ← 键)
.right ( → 键)

17.调试 template

场景:在Vue开发过程中, 经常会遇到template模板渲染时JavaScript变量出错的问题, 此时也许你会通过console.log来进行调试 这时可以在开发环境挂载一个 log 函数

// main.js
Vue.prototype.$log = window.console.log;

// 组件内部
<div>{{$log(info)}}</div>

18.img 加载失败

场景:有些时候后台返回图片地址不一定能打开,所以这个时候应该加一张默认图片

// page 代码
<img :src="imgUrl" @error="handleError" alt="">
<script>
export default{
data(){
return{
imgUrl:''
}
},
methods:{
handleError(e){
e.target.src=reqiure('图片路径') //当然如果项目配置了transformToRequire,参考上面 27.2
}
}
}

END

2
说点什么

cat1.gif doge1.gif doge2.gif 吃瓜群众.gif 哈哈.gif 微笑.gif 捂脸.gif 爷跪了.gif 示爱.png 奥特曼.png 拒绝.png 快哭了.png 鄙视.png 闭嘴.png 舔舌.png 尴尬.png 无聊.png 打脸.png 敲击.png 狗头.png 肥皂.png 口罩.png 鼓掌.png 哈哈大小.png 害羞.png 流汗.png 微笑.png 无语.png 生气.png 流口水.png 调皮.png 嘻嘻.png 可怜.png 霸气.png 困.png 傲气.png 哭泣.png 猫头.png 男亲亲.png 发怒.png 骂人.png 女亲亲.png 势利眼.png 亲亲.png 发呆.png 生病.png 草泥马.png 遗憾.png 倒霉.png 睡觉.png 思考.png 迎合.png 偷笑.png 呕吐.png 挖鼻.png 认错.png 坏笑.png 胖达.png 龇牙.png 嘘.png 阴险.png 疑问.png 左哼哼.png 晕.png 抓狂.png 猪头.png 右哼哼.png 给力.png 互粉.png 囧.png 萌.png 点赞.png 喜.png 爱你.png 心动.png 心碎.png 握拳.png 大拇指.png 胜利.png 握手.png 太阳.png 月亮.png 下雨.png 鲜花.png 多云.png 阴天.png 相机.png 音乐.png 时钟.png 合照.png
avatar
龇牙.png 表情
2 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
哈哈呃yong Recent comment authors
  Subscribe  
最新 最旧 得票最多
提醒
哈哈呃
游客
哈哈呃

哈哈

yong
游客
yong

大佬666