一次对图钉affix的改造
前言
早几天在进行个人博客的搭建,技术上用到了vue
+nuxtjs
。众所周知,身为一个成熟的脚手架,必然附带着很多可以选择的工具,就好像去菜市场带个菜筐,挑挑拣拣是免不了的。
脚手架命令一敲,让我选择的就很多,其中有一条是选择一个UI框架。
其中有几个熟悉的UI,如bootstrap,elementui。每一个我都去官网看了一遍,看了一下大家的功能和样式。其实大同小异,无非有一些组件的写法和实现方式有点差距,更大的还是样式风格的区分。

最终查看官网,满足于iview的ui组件,风格简洁,而且有一个affix(图钉)的一个组件。倒不是什么新鲜的东西,实现也不会很难,但刚好需要,它刚好在,正好就剖析一遍他们的代码,满足我博客上一个小小的需求加以改造!
为什么要看iview的源码?
一套完整的高质量组件库,一定有值得我学习的地方。
一方面是为了学习,一方面也是了解内部构造,方便接下来的改造。
我想改造个什么东西嘞?

只不过我目前实现的是一个很丑丑的...

样式什么的后期慢慢补吧,主要是想拥有一个固定位置的,能够像affix所提供的功能一样。
能够把markdown解析后生成的dom元素获取出来,生成一份目录,就可以满足文章页的需求啦。
affix的实现过程
看源码肯定要先clone一份,这里是iview源码链接
下载后找到src/components/affix
目录,发现里面有两个文件
- affix.vue
- index.js
首先打开index.js看个究竟
import Affix from './affix.vue';
export default Affix;

原来只是一个导出的文件,为了方便在src/index.js
文件里能够统一的注册组件。
这个文件里写了一个install
方法,可以自动把各个目录下的文件注册。
那么接下来具体就看一下 affix.vue
文件怎么写的:
<div>
<div ref="point" :class="classes" :style="styles">
<slot></slot>
</div>
<div v-show="slot" :style="slotStyle"></div>
</div>
---
const prefixCls = 'ivu-affix';
---
computed: {
classes () {
return [
{
[`${prefixCls}`]: this.affix
}
];
}
},
首先是template,两个div,第一个里面包含插槽,方便外部直接使用,样式什么的也有。
classes
是一个计算属性,根据this.affix
布尔值的转变,赋予div自身的class。
至于styles
这个变量,全组件一共有两个地方会修改
// Fixed Top
if ((elOffset.top - this.offsetTop) < scrollTop && this.offsetType == 'top' && !affix) {
/**中间的逻辑**/
this.styles = {
top: `${this.offsetTop}px`,
left: `${elOffset.left}px`,
width: `${this.$el.offsetWidth}px`
};
this.$emit('on-change', true);
} else if ((elOffset.top - this.offsetTop) > scrollTop && this.offsetType == 'top' && affix) {
/**中间的逻辑**/
this.styles = null;
this.$emit('on-change', false);
}
// Fixed Bottom
if ((elOffset.top + this.offsetBottom + elHeight) > (scrollTop + windowHeight) && this.offsetType == 'bottom' && !affix) {
this.affix = true;
this.styles = {
bottom: `${this.offsetBottom}px`,
left: `${elOffset.left}px`,
width: `${this.$el.offsetWidth}px`
};
this.$emit('on-change', true);
} else if ((elOffset.top + this.offsetBottom + elHeight) < (scrollTop + windowHeight) && this.offsetType == 'bottom' && affix) {
this.affix = false;
this.styles = null;
this.$emit('on-change', false);
}
代码的逻辑就是说,如果代码触碰到顶部或底部的临界点时,将this.affix
属性更改为true
,那么同时更改的还有,soltStyle
以及styles
两个属性,两个属性写好了模版上的div的样式
模版里的第二个div
也就是
<div v-show="slot" :style="slotStyle"></div>
这段代码,其中slotStyle起到一个防止塌陷的功能,因为第一个div
在fixed
状态下,会突然减少一段文档的高度和宽度,造成奇怪的bug,比如疯狂闪现,或者无法成功进行fixed定位。
在到达触发fixed
条件时,会发出一个emit事件,传给父组件,目前究竟是否还在fixed状态,实现一个事件的回调函数,方便外部处理事件。
affix解决的问题
值得一提的是,iview针对ts做了一些处理,在type目录里写了所有的d.ts文件,完善的 TypeScript 支持
我对affix的改造
- 原本的图钉,是固定在一个位置不动的,现在需要它到一个固定的位置,消失或出现,稍微修改了判断条件
- markdown文件计算出所需要创建的子节点,作为content属性直接传入,直接渲染出目录结构
- 把之前图钉存在的一些功能剔除,保留部分计算函数
- 样式文件是重写的,因为这个组件很简单,没必要复用iview的affix
- 直接对affix进行绝对定位,如果屏幕不满足展示条件就不展示
总结
这是几个月之前存在草稿箱的一次阅读源码的经历,之后也读了其他的源码,看到大佬们实现的效果和我自己写的有什么差别。
-
很多时候都是遇到问题先谷歌,然后去git搜英文单词,分析一下好不好用,拉下来试试。逐渐的觉得这种方式能解决问题,但并不快乐。
-
为了学习更多东西,在拉代码之前,先偷师一下整体结构,看看我想要的核心功能,大佬是怎么实现的。其实除了很硬核的功能,看一看还是可以看懂的,不论要不要自己去实现,偷到东西就是让人快乐的。
-
这次学习之旅是对一个小组件进行分析,像elementui,antd都有很多人去分析,看到写的文章也收获颇多,确实很多框架的架构和技巧都是值得学习的,之前的一些感悟可能也有不对的地方。
至于为什么会把这个小过程写出来,并且发出来?因为好多时候确实写得代码比这个逻辑复杂的多,其实并没能总结成文字,虽然会有肌肉记忆,但是写出来的文章,很多时候还会想再回头看一看,那就会有收获。虽然这篇水文不是为了读者哦~但如果能有一些帮助(毕竟当时就想找这么一篇文章的来着)那就更好了。
贴出来的代码片段有点散乱,酌情观看。
转载自:https://juejin.cn/post/6844904143698690056