本来是使用第三方库 vant的vue 组件库 的popup,后来在popup中使用better-scroll插件的时候,出现并不兼容的情况,也就自己搭建一个popu插件,中间遇到很多问题,都会记录一下,给自己一些总结!

popup组件实现思路

首先是模仿vant的popup组件的功能:vant-popup

1.popup组件开发与样式编写(一个遮罩层,一个显示层)。

2.组件引用(目前是选择的组件导入的方法,没有选择使用插件this.$popup(),主要是用户可以通过组件自定义传参,插件的方式不好实现)。

代码

popup.vue

<template><div >
<!--    遮罩层--><transition name="gh-fade" ><div   class="gh-overlay "v-if="isShow"ref="overlay"@click="changShowStat(false)"style="z-index: 2019;":style="overlayStyle"></div></transition><!--    内容层--><transition :name="'gh-slide-'+position"><div  class="gh-popup "v-if="isShow"ref="popup":class="[getPosition,{'gh-popup--round':round}]"style="z-index:2020":style="styles"><slot></slot><i  v-if="closeable"@click="changShowStat(false)"tabindex="0":class="{'gh-icon-cross': closeable && !closeIcon ,}"class="gh-icon  gh-popup__close-icon gh-popup__close-icon--top-right"><img v-if="closeIcon" class="gh-icon__image" :src="closeIcon" alt=""></i></div></transition></div>
</template><script>export default {name: "Popup",props:{value:Boolean,overlayStyle:{type:Object},height:{type:String,default: 'none'},width:{type:String,default: 'none'},styles:{type:Object},position:{type:String},closeable:{type:Boolean,default:false},closeIcon:{type:String},round:{type:Boolean,default:false},},data(){return{isShow:this.value}},mounted(){this.$nextTick(() => {const body = document.querySelector("body");if (body.append) {body.append(this.$el);} else {body.appendChild(this.$el);}});},beforeUpdate(){},computed:{getPosition(){return 'gh-popup--'+this.position},},watch: {//  监听value的值更新value(val) {this.isShow = val;}},methods:{changShowStat(val){this.$emit('input',false)},},}
</script><style scoped>.gh-overflow-hidden {overflow: hidden !important;}.gh-overlay {position: fixed;top: 0;left: 0;z-index: 1;width: 100%;height: 100%;background-color: rgba(0,0,0,.7);}@keyframes fadeInUp {from {opacity: 0;-webkit-transform: translate3d(0, 100%, 0);transform: translate3d(0, 100%, 0);}to {opacity: 1;-webkit-transform: translate3d(0, 0, 0);transform: translate3d(0, 0, 0);}}.fadeInUp {-webkit-animation-name: fadeInUp;animation-name: fadeInUp;animation-duration: 0.5s;}.gh-popup {position: fixed;max-height: 100%;overflow-y: auto;background-color: #fff;}.gh-popup--center {top: 50%;left: 50%;-webkit-transform: translate3d(-50%, -50%, 0);transform: translate3d(-50%, -50%, 0);}.gh-popup--top {top: 0;left: 0;width: 100%;}.gh-popup--bottom {bottom: 0;left: 0;width: 100%;}.gh-popup--left {top: 50%;left: 0;-webkit-transform: translate3d(0, -50%, 0);transform: translate3d(0, -50%, 0);}.gh-popup--right {top: 50%;right: 0;-webkit-transform: translate3d(0, -50%, 0);transform: translate3d(0, -50%, 0);}.gh-icon {position: relative;display: inline-block;font: normal normal normal 14px/1 ght-icon;font-size: inherit;text-rendering: auto;-webkit-font-smoothing: antialiased;}.gh-popup__close-icon {position: absolute;z-index: 1;color: #c8c9cc;font-size: 22px;cursor: pointer;}.gh-popup__close-icon--top-right {top: 16px;right: 16px;}.gh-icon-cross::before {content: "\2716";}.gh-icon__image {width: 1em;height: 1em;object-fit: contain;}.gh-icon::before {display: inline-block;}.gh-popup--round {border-radius: 20px 20px 0 0;}/* 内容css start*/@-webkit-keyframes gh-slide-bottom-enter {from {-webkit-transform: translate3d(0, 100%, 0);transform: translate3d(0, 100%, 0);}}@keyframes gh-slide-bottom-enter {from {-webkit-transform: translate3d(0, 100%, 0);transform: translate3d(0, 100%, 0);}}@-webkit-keyframes gh-slide-bottom-leave {to {-webkit-transform: translate3d(0, 100%, 0);transform: translate3d(0, 100%, 0);}}@keyframes gh-slide-bottom-leave {to {-webkit-transform: translate3d(0, 100%, 0);transform: translate3d(0, 100%, 0);}}@-webkit-keyframes gh-slide-top-enter {from {-webkit-transform: translate3d(0, -100%, 0);transform: translate3d(0, -100%, 0);}}@keyframes gh-slide-top-enter {from {-webkit-transform: translate3d(0, -100%, 0);transform: translate3d(0, -100%, 0);}}@-webkit-keyframes gh-slide-top-leave {to {-webkit-transform: translate3d(0, -100%, 0);transform: translate3d(0, -100%, 0);}}@keyframes gh-slide-top-leave {to {-webkit-transform: translate3d(0, -100%, 0);transform: translate3d(0, -100%, 0);}}@-webkit-keyframes gh-slide-left-enter {from {-webkit-transform: translate3d(-100%, 0, 0);transform: translate3d(-100%, 0, 0);}}@keyframes gh-slide-left-enter {from {-webkit-transform: translate3d(-100%, -50%, 0);transform: translate3d(-100%, -50%, 0);}}@-webkit-keyframes gh-slide-left-leave {to {-webkit-transform: translate3d(-100%, -50%, 0);transform: translate3d(-100%, -50%, 0);}}@keyframes gh-slide-left-leave {to {-webkit-transform: translate3d(-100%, -50%, 0);transform: translate3d(-100%, -50%, 0);}}@-webkit-keyframes gh-slide-right-enter {from {-webkit-transform: translate3d(100%, -50%, 0);transform: translate3d(100%, -50%, 0);}}@keyframes gh-slide-right-enter {from {-webkit-transform: translate3d(100%, -50%, 0);transform: translate3d(100%, -50%, 0);}}@-webkit-keyframes gh-slide-right-leave {to {-webkit-transform: translate3d(100%, -50%, 0);transform: translate3d(100%, -50%, 0);}}@keyframes gh-slide-right-leave {to {-webkit-transform: translate3d(100%, -50%, 0);transform: translate3d(100%, -50%, 0);}}@-webkit-keyframes gh-fade-in {from {opacity: 0;}to {opacity: 1;}}@keyframes gh-fade-in {from {opacity: 0;}to {opacity: 1;}}@-webkit-keyframes gh-fade-out {from {opacity: 1;}to {opacity: 0;}}@keyframes gh-fade-out {from {opacity: 1;}to {opacity: 0;}}@-webkit-keyframes gh-rotate {from {-webkit-transform: rotate(0deg);transform: rotate(0deg);}to {-webkit-transform: rotate(360deg);transform: rotate(360deg);}}@keyframes gh-rotate {from {-webkit-transform: rotate(0deg);transform: rotate(0deg);}to {-webkit-transform: rotate(360deg);transform: rotate(360deg);}}.gh-fade-enter-active {-webkit-animation: 0.5s gh-fade-in;animation: 0.5s gh-fade-in;}.gh-fade-leave-active {-webkit-animation: 0.5s gh-fade-out;animation: 0.5s gh-fade-out;}.gh-slide-top-enter-active {-webkit-animation: gh-slide-top-enter 0.5s both ease;animation: gh-slide-top-enter 0.5s both ease;}.gh-slide-top-leave-active {-webkit-animation: gh-slide-top-leave 0.5s both ease;animation: gh-slide-top-leave 0.5s both ease;}.gh-slide-bottom-enter-active {-webkit-animation: gh-slide-bottom-enter 0.5s both ease;animation: gh-slide-bottom-enter 0.5s both ease;}.gh-slide-bottom-leave-active {-webkit-animation: gh-slide-bottom-leave 1s both ease;animation: gh-slide-bottom-leave 1s both ease;}.gh-slide-left-enter-active {-webkit-animation: gh-slide-left-enter 0.5s both ease;animation: gh-slide-left-enter 0.5s both ease;}.gh-slide-left-leave-active {-webkit-animation: gh-slide-left-leave 0.5s both ease;animation: gh-slide-left-leave 0.5s both ease;}.gh-slide-right-enter-active {-webkit-animation: gh-slide-right-enter 0.5s both ease;animation: gh-slide-right-enter 0.5s both ease;}.gh-slide-right-leave-active {-webkit-animation: gh-slide-right-leave 0.5s both ease;animation: gh-slide-right-leave 0.5s both ease;}</style>

组件导入

//导入popup组件import Popup from "Popup";
//在components中注册组件components:{Popup,},
       //组件的使用<popup v-model="isShow"  //用于控制组件是否显示position="bottom"  //用于控制组件显示位置:styles="{height:'50%'}"  //组件样式></popup>

组件设计到的功能点:

1.v-model 组件之间参数双向绑定

    watch: {//  监听value的值更新value(val) {this.isShow = val;}},

methods:{
//使用$emit对父组件的v-model,通过input进行数据绑定changShowStat(val){this.$emit('input',false)},},

2.组件自定义挂载(我这里是挂载到了body下)

使用$nextTick函数,在组件更新时对组件进行自定义挂载,我看iview你们也有全局挂载,但实现思路不一样,还在研究中。。

    mounted(){this.$nextTick(() => {const body = document.querySelector("body");if (body.append) {body.append(this.$el);} else {body.appendChild(this.$el);}});},

3.vue组件过渡动画,因为开始学vue没多久,刚开始使用的js动态挂载css动画,来实现,逻辑代码写了一大堆,中间遇到很多问题,比如在watch钩子函数中,dom元素获取不到问题,还为此仔细学习了vue生命周期,最后实现了,还是出现点击频率过快,出现组件加载问题,说了很多废话,最后学习了vue的过渡动画 transition组件,来实现的。

样式写在vue组件的样式里面

参数props

参数 说明 类型 默认值
v-model 当前组件是否显示 boolean false
overlay 是否显示遮罩层 boolean true
position 弹出位置,可选值为 top bottom right left string center
overlay-style 自定义遮罩层样式 object -
round 是否显示圆角 boolean false
styles 内容层样式 boolean true
closeable 是否显示关闭图标 boolean false
close-icon  关闭图标名称或图片链接 string cross

虽然花了3天时间学了不少东西:

1.v-model 组件间的参数双向绑定

2.vue生命周期

3.vue $$nextTick函数

4.css3动画

5.vue <transition>过渡组件

6.vue插件开发

7.第三方ui库组件的引入

遇到的bug

1.props中数据只能单向传输,无法双向绑定,不要在子组件中改变props参数

2.css加载顺序问题,导致页面效果出不来,加载顺序是自上而下,渲染优先级是自下而上(类似java栈)

3.vantUI组件的popup不兼容better-scroll,所以才自己做了一个

4.页面按钮点击无效,因为使用了定位布局,父组件没有设置高度,导致无法点击

5.当自定义动画,使用js动态加载动画时,因为需要退出效果,往往在修改是否显示的参数(value)的时候,需要延时0.5秒,等动画显示完成后,再修改value的值;这时候点击过快会出现组件加载问题,考虑过使用防抖来优化,但是感觉治标不治本,后面采用了vue <transition>过渡组件。

    methods:{changShowStat(val){if(val){this.$emit('input',val)}else{setTimeout(() => {this.$emit('input',val)}, 500)}},

6.dom获取不到问题,你会发现能打印this.$refs 能够找到dom,但是就是去获取this.$refs.xxx的时候,显示undefined ,主要是 DOM结构已经出来了,但是如果在DOM结构中的某个DOM节点使用了v-if、v-show或者v-for(即根据获得的后台数据来动态操作DOM,即响应式),那么这些DOM是不会再mounted阶段找到的。参考资料,主要是dom没用挂载 最后自己也详细回顾了一下生命周期,觉得这个搞不懂,vue就算没入门;

继续学习!

vue 自定义popup组件并支持scroll组件相关推荐

  1. 很遗憾,该服务器不支持 jmail 组件!,是否支持JMAIL组件,如何使用Jmail发送邮件?...

    我司所有WINDOWS系列虚拟主机都支持JMAIL邮件发送. JMAIL邮件发送ASP示例代码如下: Set msg = Server.CreateObject("JMail.Message ...

  2. 基于 vue 编写的vue图片预览组件,支持单图和多图预览,仅传入一个图片地址,即可实现图片预览效果,可自定义背景、按钮颜色等

    hevue-img-preview 简介 完整版下载地址:基于 vue 编写的vue图片预览组件 本组件是一个基于 vue 编写的 vue 图片预览组件,支持 pc 和手机端,支持单图和多图预览,仅传 ...

  3. vue 嵌套表格组件_使用form-create动态生成vue自定义组件和嵌套表单组件

    使用form-create动态生成vue自定义组件和嵌套表单组件 maker.create 通过建立一个虚拟 DOM的方式生成自定义组件 生成 Maker let rule = [ formCreat ...

  4. vue自定义组件是.vue还是html,Vue自定义组件的四种方式示例详解

    四种组件定义方式都存在以下共性(血泪史) 规则: 1.组件只能有一个根标签 2.记住两个词全局和局部 3.组件名称命名中'-小写字母'相当于大写英文字母(hello-com 相当于 helloCom) ...

  5. vue自动滚动组件 可以支持鼠标滚轮操作

    vue自动滚动组件 可以支持鼠标滚轮操作 <!-- *@AutoScrollList *@author GYY *@date 2022/7/20 11:22 --> <templat ...

  6. Vue自定义组件npm上传私服,且从私服下载使用

    Vue自定义组件npm上传私服,yarn私服下载使用 安装镜像源管理工具nrm 发布自定义组件到公司私服 若未下载nrm源管理工具直接使用npm设置私服地址也可以 以下步骤都是基于npm命令 从私服下 ...

  7. vue可视化拖拽组件模板,vue自定义下拉框组件

    怎样利用Vue动态生成form表单 . $formCreate参数rules 表单生成规则[inputRule,selectRule,...]options 初始化配置参数(详细见底部createOp ...

  8. vue 自定义组件双向数据绑定

    文章目录 序 属性&事件传值双向绑定 v-model组件双向绑定 .sync修饰符双向绑定 总结 !!!这边文章记录的是 vue2 的概念,vue3 对双向绑定进行了改动,不要把一下代码放到 ...

  9. vue 定义全局弹框_VUE路由拦截:Vue自定义全局弹窗组件

    前言 在任何一个平台中,如果需要增加用户黏度,除了用户需要的基本内容外,用户登录注册提交信息也是非常重要的一环,可以了解用户基本信息,用户喜欢等. 抛出前后端混合开发外,vue可以轻松的实现路由拦截. ...

最新文章

  1. Java算法练习——正则表达式匹配
  2. linux_Nginx日志
  3. JavaWeb(八)——JSP(Java服务器端页面)
  4. 1079. 延迟的回文数 (20)
  5. 2017上海金马五校 购买装备 贪心+二分Check
  6. Git和SVN的区别,Git的使用方法大全
  7. 基于生成对抗网络的医学数据域适应研究
  8. 4章. 安装CentOS 5.x与多重引导小技巧
  9. 浏览器兼容性小记-DOM篇(二)
  10. 朴素贝叶斯详解及其python实现
  11. Minecraft Server 搭建手账
  12. 为什么在POS非常火爆的时候代还系统还能抢下市场呢?
  13. 椭圆是一个凸集的证明
  14. 二分法中为啥常用mid=beg+(end-beg)/2 而非mid=(beg+end)/2 ?
  15. 互联网企业盈利模式全分析
  16. 无线充电宝当无线充电器哪个品牌好?快充无线充电宝推荐
  17. 离散傅里叶变换DFT、离散余弦变换DCT、离散正弦变换DST,原理与公式推导
  18. aws WorkMail和SES实战
  19. HTTPS URL是否被加密?
  20. KPI是什么? 网站KPI指标怎么拟定?

热门文章

  1. 完成 新闻界面+一个注册界面(根据群内截图做出 相同(大体一致)的界面 ) 压缩包内有完成后的素材:样式截图3张+新闻文本txt+一个新闻页图片 注意1:在新闻界面 点击 注册用户 后跳转
  2. Linux修改资源限制详解
  3. 基于51单片机音乐盒仿真设计(音乐播放器)
  4. OBS 增加人脸特效插件
  5. 深入认识笔记本电脑的网卡
  6. nif 与 HiPE
  7. VS2015报错 error C2065:未声明的标识符错误 (__func__)
  8. 质量流量计的六种管道流体类型
  9. 如何仿真晶体管跨导gm的非线性
  10. 《能断金刚》46个商业问题解决之法