开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
前言
不甘于平庸又不努力
2023继续!!!
vue常见的一些面试问题
## vue组件的传递方式
## vue自定义指令如何实现
vue组件的传递方式
一般回答:
- Event on 传递
- 一起使用
parent.vue export default{ created(){ Event.$emit('事件名', 数据) } } 后代.vue // 后代组件都可以用 export default{ created(){ Event.$on('事件名', ()=>{}) } } - Vuex
- 安装插件
- listeners
- 多级组件嵌套传递数据时
- attrs:包含了父作用域中不被prop所识别的特性绑定(class\style除外)可以通过v-bind='$attrs'传入组件内部。配合interiAttrs选项一起使用。interiAttrs:false// 属性不显示在根元素
- listeners'传入内部组件,存放的父组件中绑定的非原生事件
parent.vue <child ref='childData' :name='names' /> child.vue <son v-bind='$attrs' /> son.vue // 可以多层后代嵌套 <div> {{$attrs}} </div> - provide / inject // 祖先组件向后代组件注入变量
- 需要一起使用
parent.vue export default{ provide: {name: ''} } 后代.vue // 后代组件都可以用 export default{ inject: ['name'] } - children ref
- 可以直接得到组件实例,使用后可以直接调用组件的方法或者访问数据
parent.vue <child ref='childData'/> <script> created(){ this.$refs.childData.init() } </script> child.vue <div @click='init(name)'></div> <script> methods:{ init(name){return name} } </script> - props $emit
- 父传子:props
parent.vue <child :name='names' /> child.vue props: ['name']- 子传父: $emit <child @click='handleClick'/>
parent.vue <child @parentClick='handleClicks'/> <script> methods:{ handleClicks(name){console.log(name)} } </script> child.vue <div @click='handleClick(name)'></div> <script> methods:{ handleClick(name){this.$emit('parentClick',name)} } </script>
总结
- 父子通信:
- 父向子传递数据是通过
props,子向父是通过events($emit);通过父链 / 子链也可以通信($parent/$children);ref也可以访问组件实例;provide/injectAPI;$attrs/$listeners
- 父向子传递数据是通过
- 兄弟通信:
- Bus;Vuex
- 跨级通信:
-
Bus;Vuex;
provide/injectAPI、$attrs/$listeners
-
vue自定义指令如何实现,实现过么
一般回答:
自定义指令分全局自定义和局部自定义。Vue.directive('指定名字',{inserted:function(el,binding){操作}}})。可以用于我们内置指定不够使用的时候自己定义。定义出来的使用方式就如同v-if v-for等等。
directive中可以使用以下几个可选钩子函数
- bind: 只调用一次,指令第一次绑定到元素上时调用。可以进行一次性的初始化设置
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)
- update:所在组件的VNode更新时调用,但是可能发生在VNode更新之前,指令的值可能发生了该表,也可能没有
- componentUpdate: 指令所在组件的VNode及其子VNode全部更新后调用
- unbind: 只调用一次,指令与元素解绑时调用
钩子函数参数
- el: 指令所绑定的元素。可以用来直接操作DOM
- binding: 一个对象,包含以下property
- name: 指令名,不包含v-前缀
- value: 指令的绑定值。eg: v-demo='2' ,绑定值为2
- oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用
- expression:字符串形式的指令表达。v-demo='1+1'.表达式为1+1
- arg:传给指令的参数。可选
- modifiers: 一个包含修饰符的对象。eg:v-demo.foo.bar修饰符对象为{foo:true,bar:true}
- vnode: Vue编译生成的虚拟节点
- oldVnode: 上一个虚拟节点, 仅在update和componentUpdated钩子中可用。
示例:
<div id="app">
<div v-color="direColor">定义v-color指令,根据变量变换颜色</div>
</div>
<script>
Vue.directive('color', {
inserted: function (el, binding) {
console.log(el, binding)
el.style.color = binding.value
}
})
const vm = new Vue({
el: '#app',
data() {
return {
name: '张三',
direColor: '#d117e6'
}
},
})
实现过一些简单的操作指定:
吸顶
<div v-stickyed="{top:0}" style="width:1000px;height:40px;background:red;margin-left:200px;z-index:1001"></div>
Vue.directive('stickyed', {
inserted(el, binding) {
el.style.position = 'sticky' //position 的 属性 非常好用
console.log(binding, '0000')
function aaa() {
const scroll_top = document.documentElement.scrollTop
const offset_top = el.offsetTop
console.log(scroll_top, '滚动条滚动得距离')
console.log(offset_top, '元素距离顶部得距离')
if (offset_top - scroll_top < 0) {
el.style.top = binding.value.top + 'px'
}
}
window.addEventListener('scroll', aaa, false) //实施滚动条监听
}
})
nav的切换
<div id="app">
<div v-color="direColor">定义v-color指令,根据变量变换颜色</div>
<br>
<ul class="nav-ul" v-nav-status="{currentIndex,className: 'nav-default', activeName: 'nav-active'}">
<li v-for="(item, index) of list" :key="index" class="nav-default" @click="changeNav(index)">
{{item}}
</li>
</ul>
</div>
<script>
Vue.directive('navStatus', {
bind(el, binding) {
const _value = binding.value
const cn = el.getElementsByClassName(_value.className)
console.log('el', el)
cn[_value.currentIndex].className += ` ${_value.activeName}` // 初始化。默认第一个为默认状态 不一样的背景色
},
update(el, binding) {
const _value = binding.value
const _oldValue = binding.oldValue
const cn = el.getElementsByClassName(_value.className)
console.log('el', el)
cn[_oldValue.currentIndex].className = `${_value.className}` // 取消前一个tab的背景色
cn[_value.currentIndex].className += ` ${_value.activeName}` // 设置点击的tab为选中色
}
})
const vm = new Vue({
el: '#app',
data() {
return {
currentIndex: 0,
list: ['导航1', '导航2', '导航3', '导航4', '导航5']
}
},
methods: {
changeNav(i) {
this.currentIndex = i
},
}
})
</script>
省略指令
<div class="ellipsis" v-ellipsis:200>一堆文字</div>
Vue.directive('ellipsis', {
inserted: function (el, binding) {
el.style.width = binding.arg || 100 + 'px'
el.style.whiteSpace = 'nowrap'
el.style.overflow = 'hidden';
el.style.textOverflow = 'ellipsis';
}
})
返回顶部按钮 隐藏消失
<div class="fixed-right" v-show="isShow.value" v-scroll-show="isShow" @click="handleTop(0)">回到顶部</div>
> data:
isShow: {
value: false
}
Vue.directive('scroll-show', {
inserted(el, binding) {
let scope = binding.arg || '200';
window.addEventListener('scroll', function (e) {
if (this.scrollY > Number(scope)) {
binding.value.value = true
} else {
binding.value.value = false
}
})
},
})
返回顶部
Vue.directive('back-top',{
inserted(el,binding) {
let e = binding.arg || 'click'
el.addEventListener(e, function () {
let scrollToptimer = setInterval(function () {
let top = document.documentElement.scrollTop + document.body.scrollTop
let speed = top / 4
top -= speed
document.documentElement.scrollTop = document.body.scrollTop = top
if (top == 0) {
clearInterval(scrollToptimer)
}
}, 30)
})
}
})
防抖
<button v-debounce="handleClick">点击登录按钮</button>
handleClick() {
console.info('点击登录按钮')
},
Vue.directive('debounce', {
inserted(el, binding) {
let timer
el.addEventListener('click', () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() =>{
binding.value()
}, 1000)
})
},
})
权限操作指令
说明:可以根据后台返回的账号的状态进行限制是否显示,可以避免写太多的v-if v-else
<ul class="nav-ul">
<li v-for="(item, index) of arr" :key="index" v-permission="item.status">
{{item.name}}
</li>
</ul>
> data:
arr: [
{name: 'admin1', status: 1},
{name: 'admin2', status: 2},
{name: 'user', status: 0},
{name: 'admin4', status: 3},
]
Vue.directive('permission', {
inserted(el, binding) {
const status = binding.value
if (parseInt(status) === 0) {
el.parentNode && el.parentNode.removeChild(el) // 找到
}
},
})
后记
本文仅作为自己一个阅读记录,具体还是要看大佬们的文章