自定义popup写法以及点击backdrop隐藏popup的directive写法

本文介绍如何通过templateURL自定义Ionic中的Popup样式,包括编写HTML文件定义样式与内容、在JS中调用自定义的Popup文件及使用Directive实现点击Popup外部关闭的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

网上提供的popup例子使用的是template,使用title、subtitle等参数来设置样式,但是这样在很多时候并不能满足我们的需求的(ionic自带样式本身就丑),所以这时候可以通过templateURL来写出我们想要的样式。

效果

原样式:

223817_YS13_2493500.png

自定义后的样式(不敢说有多好看,但是至少还是有点进步的):

223827_qEwL_2493500.png

实现

一.建立一个popup.html文件

里面编写自己想要的内容与效果,由于我这里就一个标题和input框,所以代码量较少。如下:

<style>
.popup-title{
   padding-bottom: 10px;
}

</style>
<div>请填写快速按钮标题</div>
<input type="text" />

二.在JS中调用此popup文件

代码为:

$scope.myPopup = $ionicPopup.show({           
    templateUrl: 'templates/sale/modal/popup.html',
    scope: $scope,
    buttons: [{ //Array[Object] (可选)。放在弹窗footer内的按钮。
        text: '取消',
        type: 'sale-cancel',
        onTap: function(e) { 
            $scope.myPopup.close();  
        } 
    }, {
        text: '确定',
         type: 'sale-sure',
               onTap: function(e) { 
            console.log(e)
        }
    }]
});

可以看到,button里的内容也是可以自定义的,type对应的就是button的样式class,所以这里需要编写一个css文件,我修改了一下popup的border-radius,这个是需要覆盖源码的,请知悉。代码如下:

.popup-container .popup {
    border-radius: 8px;
}
.popup-buttons {
    padding: 0;
    min-height: auto;
}
.sale-cancel {
    border-bottom-left-radius: 8px!important;
    margin-right: 0!important;
}
.sale-sure {
    border-bottom-right-radius: 8px!important;
    background-color: #EABA82;
    color: white!important;
}

注:使用!important的目的是使其样式优先级最高,并且在状态为active时不改变对应的样式。

Directive

       在我个人的操作习惯来说,弹起这个弹窗的时候,如果我想取消本次弹窗,我是想点击这个弹窗的外部就可以取消,而不是说非要点击那个取消按钮,并且现在有很多的大屏手机,一般单手操作的话是不容易点击到取消的。

       但是在ionic的popup组件中是没有这样的效果的,所以我们需要自己去实现这个效果,这里使用directive来实现。

一.在app.js中定义一个module来存储这个directive,如下:

var saleDrective = angular.module('saleDrective', ['saleDrective.directives']);

二.建立js文件,加入以下代码:

angular.module('saleDrective.directives', []) 
  .directive('rjCloseBackDrop', [function() {
    return {     
        scope: false,
             restrict: 'A',
             replace: false,
             link: function($scope, iElm, iAttrs, controller) {       
            var htmlEl = angular.element(document.querySelector('html'));       
            htmlEl.on("click", function(event) {         
                if (event.target.nodeName === "HTML" & $scope.myPopup) {
                    $scope.myPopup.close();
                }       
            });     
        }   
    }; 
}])

这里的module名字需要与app.js定义的保持一致。Directive是直接操作dom的,判断当前popup为显示状态时(即下面的if语句,$scope.myPopup是在controller中定义popup名字,在上面代码中有写出来)点击外围backdrop即close当前popup。

三.在HTML中引入这个directive

在使用到这个popup对应的页面中的content上加入rj-close-back-drop如:

223837_3vM3_2493500.png

四.在index中引入这个js文件

现在就大功告成了,希望对大家有帮助。

 

 

 

 

转载于:https://my.oschina.net/keysITer/blog/611551

<think>我们计划实现一个点击弹窗外部关闭弹窗的功能。根据引用内容,核心思路是: 1. 监听整个文档的点击事件 2. 判断点击事件发生的元素是否在弹窗内部 3. 如果在外部,则关闭弹窗 具体实现方式有两种常见方法: 方法一:使用contains方法 - 给弹窗添加一个ref,用于获取弹窗的DOM元素 - 在mounted中监听document的click事件 - 在事件处理函数中,判断事件目标是否在弹窗内(使用弹窗DOM的contains方法) - 如果不在,则关闭弹窗 方法二:使用自定义指令(Vue推荐方式) - 可以封装一个自定义指令,例如v-click-outside - 指令绑定到弹窗元素上,当点击外部时执行绑定的方法 另外,根据引用[4],如果使用Element UI等组件库,可以通过设置close-on-click-modal属性来控制点击外部是否关闭弹窗。但这里我们讨论的是自己实现弹窗的情况。 下面我们分别用两种方式实现: 方法一:在组件内直接实现(不封装指令) 步骤: 1. 在弹窗组件的模板中,给最外层容器添加一个ref,例如ref="popup" 2. 在mounted生命周期钩子中添加document的点击事件监听 3. 在事件处理函数中,检查事件目标是否在弹窗内,如果不在则触发关闭 4. 在beforeDestroy生命周期钩子中移除事件监听 注意:为了避免在弹窗打开后立即触发外部点击(因为事件冒泡),我们可以在打开弹窗时延迟添加监听,或者通过一个标志位控制。 方法二:封装自定义指令(推荐,可复用) 自定义指令v-click-outside的实现: 1. 创建一个指令对象,包含bind和unbind钩子 2. 在bind钩子中,为document添加点击事件监听 3. 在事件处理函数中,判断点击的目标是否在指令绑定的元素内部(或指令绑定的元素本身),如果不在,则调用绑定的表达式(即关闭弹窗的方法) 4. 在unbind钩子中,移除事件监听 我们以方法二为例,详细说明如何实现自定义指令。 下面是一个完整的Vue2示例,包括自定义指令和弹窗组件的使用。</think># 点击弹窗外部关闭弹窗功能的实现方案 在网页开发中,实现点击弹窗外部关闭弹窗的功能是常见的交互需求。下面我将详细介绍几种实现方法,并提供一个完整的Vue2实现示例。 ## 实现原理分析 根据引用内容,实现点击弹窗外部关闭弹窗的核心原理是: 1. 监听全局点击事件(document或window) 2. 判断点击位置是否在弹窗外部(使用`contains`方法) 3. 如果是外部点击,则关闭弹窗 ## 实现方案对比 | 方法 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | 原生JS实现 | 轻量,无需依赖 | 需要手动管理事件监听 | 简单页面或小型项目 | | 自定义指令 | 可复用,封装性好 | 需要额外代码 | Vue项目,需要多处使用 | | 组件库配置 | 简单,一行代码 | 依赖特定UI库 | 使用Element UI等组件库的项目 | | 事件委托 | 性能较好 | 实现相对复杂 | 需要优化性能的场景 | ## Vue2实现示例 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>点击外部关闭弹窗 - Vue2实现</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: &#39;Segoe UI&#39;, Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f1 100%); min-height: 100vh; padding: 20px; display: flex; justify-content: center; align-items: center; color: #333; } .container { max-width: 1200px; width: 100%; padding: 30px; } header { text-align: center; margin-bottom: 40px; padding: 30px; background: white; border-radius: 12px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08); } h1 { font-size: 2.8rem; margin-bottom: 15px; color: #3498db; font-weight: 600; } .subtitle { font-size: 1.2rem; color: #7f8c8d; max-width: 800px; margin: 0 auto 20px; } .methods { display: flex; flex-wrap: wrap; gap: 30px; margin-bottom: 50px; } .method-card { background: white; border-radius: 12px; padding: 30px; flex: 1; min-width: 300px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease, box-shadow 0.3s ease; } .method-card:hover { transform: translateY(-5px); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15); } .method-card h2 { margin-bottom: 20px; color: #3498db; padding-bottom: 15px; border-bottom: 3px solid #3498db; } .method-card ul { padding-left: 25px; margin: 20px 0; } .method-card li { margin: 15px 0; line-height: 1.6; } .highlight { background: #e3f2fd; padding: 2px 6px; border-radius: 4px; font-family: monospace; } .demo-area { background: white; border-radius: 12px; padding: 40px; margin-top: 30px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1); text-align: center; } .demo-area h2 { color: #3498db; margin-bottom: 30px; } .btn { background: #3498db; color: white; border: none; padding: 12px 30px; font-size: 1.1rem; border-radius: 50px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3); } .btn:hover { background: #2980b9; transform: translateY(-3px); box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4); } .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } .modal { background: white; border-radius: 12px; padding: 30px; width: 90%; max-width: 500px; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3); position: relative; animation: modalAppear 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @keyframes modalAppear { from { opacity: 0; transform: translateY(30px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } } .modal h3 { font-size: 1.8rem; margin-bottom: 20px; color: #2c3e50; } .modal p { line-height: 1.8; margin-bottom: 25px; color: #555; } .close-btn { position: absolute; top: 20px; right: 20px; background: none; border: none; font-size: 1.5rem; color: #7f8c8d; cursor: pointer; transition: color 0.2s; } .close-btn:hover { color: #e74c3c; } .code-block { background: #2c3e50; color: #ecf0f1; padding: 20px; border-radius: 8px; text-align: left; margin: 20px 0; font-family: &#39;Fira Code&#39;, monospace; font-size: 0.95rem; overflow-x: auto; } .code-comment { color: #95a5a6; } .footer { text-align: center; margin-top: 40px; padding: 20px; color: #7f8c8d; font-size: 0.9rem; } @media (max-width: 768px) { .methods { flex-direction: column; } .method-card { min-width: 100%; } h1 { font-size: 2rem; } } </style> </head> <body> <div id="app"> <div class="container"> <header> <h1>点击外部关闭弹窗功能实现</h1> <p class="subtitle">多种方法实现点击弹窗外部区域关闭弹窗的交互效果</p> </header> <div class="methods"> <div class="method-card"> <h2>方法一:原生JS实现</h2> <p>使用原生JavaScript实现点击外部关闭弹窗功能:</p> <ul> <li>监听document的点击事件</li> <li>使用<strong>contains</strong>方法判断点击位置</li> <li>简单直接,无需依赖</li> </ul> <div class="code-block"> <span class="code-comment">// 添加全局点击事件监听</span><br> document.addEventListener(&#39;click&#39;, (e) => {<br>   if (modal.value && !modal.value.contains(e.target)) {<br>     closeModal();<br>   }<br> }); </div> </div> <div class="method-card"> <h2>方法二:Vue自定义指令</h2> <p>创建可复用的自定义指令:</p> <ul> <li>封装点击外部关闭逻辑</li> <li>可在多个组件中复用</li> <li>符合Vue的设计理念</li> </ul> <div class="code-block"> <span class="code-comment">// 自定义指令实现</span><br> Vue.directive(&#39;click-outside&#39;, {<br>   bind(el, binding) {<br>     el.clickOutsideEvent = (e) => {<br>       if (!el.contains(e.target)) {<br>         binding.value(e);<br>       }<br>     };<br>     document.addEventListener(&#39;click&#39;, el.clickOutsideEvent);<br>   },<br>   unbind(el) {<br>     document.removeEventListener(&#39;click&#39;, el.clickOutsideEvent);<br>   }<br> }); </div> </div> <div class="method-card"> <h2>方法三:组件库配置</h2> <p>使用Element UI等组件库时:</p> <ul> <li>通过属性配置关闭行为</li> <li>一行代码即可实现</li> <li>依赖特定UI库</li> </ul> <div class="code-block"> <span class="code-comment">// Element UI 配置方式</span><br> <el-dialog <br>   :visible.sync="dialogVisible"<br>   <span class="highlight">:close-on-click-modal="false"</span>><br>   弹窗内容<br> </el-dialog> </div> </div> </div> <div class="demo-area"> <h2>功能演示</h2> <p>点击下方按钮打开弹窗,然后尝试点击弹窗外部区域关闭它</p> <button class="btn" @click="showModal = true">打开弹窗</button> <!-- 弹窗组件 --> <div class="modal-overlay" v-if="showModal" v-click-outside="closeModal"> <div class="modal" ref="modal"> <button class="close-btn" @click="closeModal">×</button> <h3>点击外部关闭弹窗演示</h3> <p>这是一个演示弹窗,您可以通过以下方式关闭它:</p> <ul> <li>点击右上角的关闭按钮</li> <li>点击弹窗外部区域</li> <li>按ESC键(需额外实现)</li> </ul> <p>当前实现使用了自定义指令 <span class="highlight">v-click-outside</span> 来监听外部点击事件。</p> <div class="code-block"> <span class="code-comment">// 使用自定义指令</span><br> <div v-click-outside="closeModal"><br>   <span class="code-comment"><!-- 弹窗内容 --></span><br> </div> </div> </div> </div> </div> <div class="footer"> <p>Vue2点击外部关闭弹窗实现 | 包含多种实现方案 | 点击弹窗外部区域体验效果</p> </div> </div> </div> <script> // 注册自定义指令 Vue.directive(&#39;click-outside&#39;, { bind(el, binding, vnode) { // 点击事件处理函数 el.clickOutsideEvent = function(event) { // 检查点击是否发生在元素外部 if (!(el === event.target || el.contains(event.target))) { // 调用绑定的方法 binding.value(event); } }; // 添加事件监听 document.body.addEventListener(&#39;click&#39;, el.clickOutsideEvent); }, unbind(el) { // 移除事件监听 document.body.removeEventListener(&#39;click&#39;, el.clickOutsideEvent); } }); // 创建Vue实例 new Vue({ el: &#39;#app&#39;, data: { showModal: false }, methods: { closeModal() { this.showModal = false; } }, mounted() { // 添加ESC键关闭功能 document.addEventListener(&#39;keydown&#39;, (e) => { if (e.key === &#39;Escape&#39; && this.showModal) { this.closeModal(); } }); } }); </script> </body> </html> ``` ## 实现细节说明 ### 1. 原生JS实现方法 核心代码: ```javascript document.addEventListener(&#39;click&#39;, (e) => { if (modalRef.value && !modalRef.value.contains(e.target)) { closeModal(); } }); ``` ### 2. Vue自定义指令实现 自定义指令封装: ```javascript Vue.directive(&#39;click-outside&#39;, { bind(el, binding) { el.clickOutsideEvent = (e) => { if (!el.contains(e.target)) { binding.value(e); } }; document.addEventListener(&#39;click&#39;, el.clickOutsideEvent); }, unbind(el) { document.removeEventListener(&#39;click&#39;, el.clickOutsideEvent); } }); ``` 使用方式: ```html <div v-click-outside="closeModal"> <!-- 弹窗内容 --> </div> ``` ### 3. 组件库配置方法(以Element UI为例) ```html <el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false"> 弹窗内容 </el-dialog> ``` ## 注意事项 1. **事件冒泡处理**:确保弹窗内部元素不会触发外部点击事件 2. **性能优化**:及时移除事件监听,避免内存泄漏 3. **移动端适配**:在移动设备上可能需要处理touch事件 4. **无障碍访问**:确保键盘操作也能关闭弹窗(如ESC键) ## 常见问题解决 1. **弹窗内部点击也会触发关闭**: - 检查事件冒泡,确保内部点击不会传播到document - 使用`e.stopPropagation()`阻止事件冒泡 2. **多个弹窗冲突**: - 使用z-index控制层级 - 只监听最上层弹窗的外部点击 3. **性能问题**: - 只在弹窗显示时添加事件监听 - 使用事件委托优化 ## 相关扩展功能 1. **ESC键关闭弹窗**: ```javascript document.addEventListener(&#39;keydown&#39;, (e) => { if (e.key === &#39;Escape&#39; && showModal) { closeModal(); } }); ``` 2. **滑动关闭**(移动端): ```javascript let startY = 0; modal.addEventListener(&#39;touchstart&#39;, (e) => { startY = e.touches[0].clientY; }); modal.addEventListener(&#39;touchmove&#39;, (e) => { if (e.touches[0].clientY - startY > 100) { closeModal(); } }); ``` 3. **背景模糊效果**: ```css .modal-overlay { backdrop-filter: blur(5px); } ``` 这个实现方案提供了多种方法来实现点击弹窗外部关闭功能,您可以根据项目需求选择最适合的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值