从组件的编写到组件间的通信到使用LESS开发样式,再到使用发布订阅模式,借助vue数据响应式原理实现手风琴式(打开一栏其余栏自动关闭)的折叠面板和菜单栏,开发中的各种细节都会阻碍开发的正常进度,做到高效率开发⛏
效果图
页面由开发完成的组件而编写的,有兴趣预览可以打开Vue App (sina-ui.vercel.app)已部署到vercel(免费部署还不行动起来✨)源码可戳学习组件开发🎉 (github.com),文档还在完善,组件还在开发,有兴趣的小伙伴欢迎加入🎊讨个star
回忆组件开发
菜单
使用插槽,目前开发的时候就只用到了匿名插槽和具名插槽,另外一个作用域插槽还没有用到,开发的时候遇到的场景,大多数是对样式的,比如对插槽的样式怎么定义,知道直接对插槽进行样式设置没有效果,我们选择在外面包裹一层直接对外层设置样式来实现(当时就很多场景一时间想不起来了)。
菜单的高亮怎么实现?一开始想到的是使用一个全局变量来记录当前的高亮下标,开始动手,做了一会看效果发现,点击一个亮一个,其他没有消除高亮,噢,这个变量发生变化了必须得通知其他子菜单项啊,想了想vue的原理和最近看到的一篇文章——发布订阅模式,(拍手)试试发布订阅模式,给每一个子菜单项都订阅上,当子菜单项被点击了我就改变eventBus.js的变量,借助vue响应式原理用到的Object.defineProperty,变量一变触发set,然后触发【发布】,这样每一个子菜单项就都被通知了那个全局变量发生变化了,我们得重新渲染,但是这个重新渲染靠什么触发嘞,想到了,使用vue本身的变量不就好了吗,看代码,就是currentIndex,成功实现,撒花🎊
路由跳转怎么实现?通过index进行,所以index连接路由跳转名,暂时是这样
/** 菜单被点击 修改默认高亮键值 通过事件总线沟通 触发了setter 修改-> 发布出去*/
const clickMenu = () => {
current.index = props.index;
if(current.router == "true") router.push(`/${props.index}`)
}
/** 指定高亮键值变换时的操作 */
const user1 = (content) => {
currentIndex.value = content;
};
/** 订阅 */
eventEmitter.on('article', user1);
上传
我们知道原生的上传input框很丑,所以如何把它变好看呢?没错,隐藏起来,隐藏的方法有display:none;visibility:hidden;或者是透明度opacity为0,或者使用绝对布局移出当前页面等等。但是我们需要点击就能触发所以隐藏元素的点击事件必须在并且在合理的位置上,所以使用透明度!外加相对绝对布局
如何处理获取的图片呢?通过vue提供的ref获取DOM节点直接进行操作,注意最早能操作DOM的时候是onMounted(vue3)/mounted(vue2)不然会报错,因为虚拟DOM节点还未替换el挂载到真的DOM树上,所以我们操作不了。
const handleUploadFile = () => {
const imgfile = file.value.files[0];
reads.readAsDataURL(imgfile);
reads.onload = function () {
img.value.src = this.result;
imgTitle.value = file.value.files[0].name;
visibility.value = true;
}
}
回到顶部
由使用组件的人传入visibilityHeight即滚动到什么程度就出现回到顶部按钮,在onMounted里添加监听滚动条的事件,对滚动的对象进行设置,这里需要了解视窗的概念,这里可以参考其他作者汇总的一张图,scrollTop大于设定的高度就出现,使得
onMounted(() => {
document.documentElement.style.scrollBehavior = 'smooth';
window.addEventListener('scroll', handleBackTopVisibility, true);
})
const handleBackTopVisibility = () =>{
visibility.value = document.documentElement.scrollTop > props.visibilityHeight.split('px')[0] ? true : false;
}
const handlebackTop = () => {
document.documentElement.scrollTop = 0;
ctx.$emit('backTop');
}
折叠面板
使用手风琴式添加accordion字段实现,和菜单栏一样,不一样在于判断是否是需要手风琴式
/** 指定展开时的操作 */
const user = (content) => {
if (content.ifAccordion) { // 1. 是手风琴
visibility.value = content.index == props.name ? !visibility.value : true;
} else { // 2. 不是手风琴
if (props.name === content.index) {
visibility.value = !visibility.value;
}
}
};
eventEmitter.on('article', user);
发布组件到NPM
- 注册npm
- 终端登录
- npm publish
- 注:版本号需要迭代 组件发布,我选择循环,代码目录如下,太多我就以发布三个为例,触发脚本流程:先触发打包然后运行index.js
import NAvater from './NAvatar/index.vue';
//
import NBackTop from './NBackTop/index.vue';
//
import NButton from './NButton/index.vue';
const components = [
NAvater,
NBackTop,
NButton
]
// 定义 install 方法,接收 Vue 作为参数。如果使用 use 注册插件,则所有的组件都将被注册
const install = function (Vue) {
// 遍历注册全局组件
components.forEach(component => {
Vue.component(component.name, component)
})
// 判断是否是直接引入文件,如果是,就不用调用 Vue.use()
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
}
// 导出的对象必须具有 install,才能被 Vue.use() 方法安装
export default {
install
}
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lib": "vue-cli-service build --target lib packages/index.js"
},
总结
- 开发组件过程中,学到了如何去实际开发一个组件(这不是废话),深入vue,了解其原理比如响应式,利用它!将开发模式用于实践,发布订阅模式听过了无数次不如实践一次,vue自带的处理样式的指令v-bind:class/:class,HTML标签的一些属性,比如img的object-fit,如何清除原生标签样式,flex布局,使用LESS实际开发,vue组件的通信,我的环境是vue3+setup所以需要了解新的定义方式,使用了事件总线和props/emit进行。ref.value总是忘记带.value后来发现可以借助插件,后面vue也提供了另外的方式定义$ref()就可以不带.value,了解浏览器原生操作DOM的方式,视窗,文件流的获取,文档碎片创建table组件的行等等。
- 组件发布过程中,因为组件name是必须的,而我使用了vue3的setup所以就需要其他处理name的方式,经过查阅发现,可以使用第三方Npm包在进行vite配置,或者是使用vue2的形式,再者就另外添加一个‘script’标签,不然的话就是无效果。
- 自己编写一个组件,从开发到落地到发布,到文档。自己开发一个组件思考尤其多,基本不扎实就总要baidu,非常消耗时间,所以基础还是需要时常巩固故滴。
- 感谢你能看到这里🙇