关于 popup 浮动弹出组件的实现
场景需求(浮出覆盖:vue-popper
)
我们经常有实现一些浮动弹窗的需求,比如在一个图表里当鼠标悬浮在某个位置上时有自动浮窗提示。
在Element-ui
里,也有多个组件属于浮动弹窗类型,比如el-popover
、el-tooltip
等。
查询源代码发现,背后是基于vue-popper.js
这个库,而这个库是对popper.js
库的一个 vue 封装。
基于此,如果我们只是想实现浮窗,只需要使用vue-popper.js
即可,也十分方便。
场景选择(浮出不覆盖:自定义的popup
)
一般来说,浮窗组件是鼠标滑到哪,哪里就出现,出现的浮窗会覆盖目前的视窗。但有时,这会导致不是很美观。
在我的个人博客里,我在页面底部栏里加入了几个二维码,默认是不显示的。当鼠标划过其中某个触点(比如微信文字)时,该二维码(即微信二维码)浮出,由于布局原因,我发现这个二维码直接显示在布局内(而非浮动覆盖)会更好一些。
基于此,我简单封装了自己的popup
组件,这个对相应要哦浮出的元素只是简单做了一个默认不显示、触发显示的处理。但很好地满足了自己的需求。
关于跨平台文件流相关api
问题
具体情况
在我一开始的程序设计中,前端使用的是基于js
的nuxt
后端使用的是基于python
的fastapi
。
后来经过analyze
发现,element-ui
和ali-oss
两个包占了很大的空间。
我通过babel
的按需导入,成功压缩了element-ui
的体积量。考虑到ali-oss
非前端 UI 组件,也非build
必需模块,而是一个api
,因此想将ali-oss
整体移植到后端中。
python
平台需要cmcmod
的问题
根据ali-oss
官方文档,是有python
版本的。
但很快就遇到了两个问题,首先是版本,它只支持2.7
及最高3.6
。
后来检查发现,我本地安装的是3.7
,服务端安装的是3.6
,服务端那边版本倒不是问题,本地其实无所谓。
但是,更关键的一个问题出现了。
linux
环境下需要单独安装python-dev
,以使C++
加速的cmcmod
更快,否则ali-oss
将会使用纯python
计算,速度会慢上数十倍。
我尝试了安装多遍,都未能解决问题,后来提交了工单,交涉了多日,依旧无果。
尽管如此,我想抱着暂时先用的想法,结果碰到了一个更棘手的技术相关的问题。
js
的和python
之间的数据交换没有想象中那么简单
我简单设计了一个较为稳健的图片上传的api
,基于fastapi
,它支持上传本地图片、网络图片和二进制图片内容。
在移除了ali-oss
的js
依赖后,我打算使用axios
直接与其交互。
结果发现element-ui
读取到的图片是File
格式,而这个格式是js
特有的,需要通过FileReader
或其它方式进行转换才能与python
进行交互。
具体,binaryString
格式并非python
的bytes
,而url
是blob url
,并且是本地的localhost
,在开发的时候并不能直接被nanchuan.site
读取。
解决方案
我相信,肯定有一些方法可以将js
的File
格式转换成python
的bytes
等形式,但我觉得,这中间的成本有一些些高了。在考虑到python
版本的性能问题之后,我决定放弃python
的sdk
。
基于此,我打算暂时先使用js
的ali-oss-sdk
,等之后项目进度放缓时,再对应配置koa
版本的后台。
对此,我唯一的顾虑就是,fastapi
之后要不要作为本项目的后端,这将是一个需要思考的问题。
关于局部滚动与滚动条问题
关于百度统计在nuxt
中的最佳植入形式
首先,如果按照百度统计官方的推荐做法,可以将代码插入到html
模板的head
标签前,即充当整个网站第一个运行的函数。
但nuxt
是较高封装的框架,html
层基本都是不用考虑的,但要实现这个需求,也不是不可以。
方法一:修改app.html
nuxt
默认以nuxt
内部的app.template.html
文件启动。
<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
路径很深,但我们并不需要直接修改这个文件(虽然我确实傻到修改过)。
我们可以在项目的根目录创建一个app.html
文件,内容同上,等价于直接覆盖。
在此基础上插入百度的官方代码,如下。
<!DOCTYPE html>
<script>
var _hmt = _hmt || []
;(function () {
var hm = document.createElement('script')
hm.src = 'https://hm.baidu.com/hm.js?【这里是代码序列号】'
var s = document.getElementsByTagName('script')[0]
s.parentNode.insertBefore(hm, s)
})()
</script>
<html {{ HTML_ATTRS }}>
<head {{ HEAD_ATTRS }}>
{{ HEAD }}
</head>
<body {{ BODY_ATTRS }}>
{{ APP }}
</body>
</html>
方法二:在nuxt.config.js
的head
中植入代码
nuxt.config.js
的扩展能力还是很强的,其中有一个配置项是head
,主要用来配置一些settings
数据,详情可见 The head Property - NuxtJS。
但官方只提供了配置settings
的示例,其实还可以加入script
,只不过要以src
的形式。也就是说,上述方法中的一串代码并不能直接拷贝过来。
但在我仔细分析了百度官方的这串代码后,才意识到,它只是自动把百度的这段代码插入到html
的第一个script
位置而已。如果我们的脚本本来就是位于网页的第一个位置,那这个脚本就有点多余了。它的核心其实就一句话,就是hm.src = 'https://hm.baidu.com/hm.js?【这里是代码序列号】'
。
基于此认知,我们只需要把这个网址复制出来,配置到head.script
里去就可以了。具体如下。
// ** See https://nuxtjs.org/api/configuration-head
head: {
title: '南川笔记' || process.env.npm_package_name,
description: '南川笔记——致力于知识服务',
settings: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
script: [
// 用于百度统计
{
src:
process.env === 'production'
? 'https://hm.baidu.com/hm.js?【这里是代码序列号】'
: '',
},
],
},
这里,值得注意的是,如果在开发模式(本地浏览器)运行nuxt
程序,该脚本依旧会触发百度的统计机制,并且在浏览器的storage/session
中注入cookie
,引发浏览器的跨域警告。
在这里,我也意识到了,之前我的百度统计页面为啥会出现大量的localhost
访问了,我还好奇为啥百度能检测到localhost
的访问来着。
由于在开发模式下,本身就不需要进行访问统计,因此,我们可以加入一句 process.env === 'production'
进行判断,如果是开发模式就不植入脚本了。
最后,完美解决问题。如下,在开发模式下,脚本是不会运行的。
关于nuxt-content
的渲染
原来是通过读取document.body
里的内容(由md
渲染后的markdown
)。
具体可以见:
render (h, { data, props }) {
const { document } = props
const { body } = document || {}
if (!body || !body.children || !Array.isArray(body.children)) {
return
}
...
return h('div', data, body.children.map(child => processNode(child, h, document)))
}
JS 总有奇怪的设计问题
看一段代码。
const langs = ['en', 'zh'];
langs.forEach((lang) => {
console.log({lang: lang});
});
这段代码如果按照python
之类语言的逻辑,毫无疑问会输出
{ 'en': 'en'}
{ 'zh': 'zh'}
然而在javascript
里,得到的结果却是
{'lang': 'en'}
{'lang': 'zh'}