如何使用 angularJS 将可拖动指令应用于引导模式?
Posted
技术标签:
【中文标题】如何使用 angularJS 将可拖动指令应用于引导模式?【英文标题】:How can i apply a draggable directive to bootstrap modal using angularJS? 【发布时间】:2015-03-12 14:14:34 【问题描述】:我在我的 Angular 应用程序中使用引导模式,它工作正常。我需要让它可拖动和调整大小,所以我定义了一个指令。现在的问题是它被应用于模态窗口内的内容,因此模态窗口变得透明。
如何在打开窗口时将可拖动指令分配给模态窗口? 这是代码,
HTML:
<div ng-controller="CustomWidgetCtrl">
<div class="box-header-btns pull-right" style="top:10px" >
<a title="settings" ng-click="openSettings(widget)"><i class="glyphicon glyphicon-cog"></i></a>
</div>
</div>
App.js:
var routerApp = angular.module('DiginRt', ['ui.bootstrap','ngRoute']);
routerApp.controller('CustomWidgetCtrl', ['$scope', '$modal',
function($scope, $modal)
$scope.openSettings = function(widget)
$modal.open(
scope: $scope,
templateUrl: 'chart_settings.html',
controller: 'chartSettingsCtrl',
resolve:
widget: function()
return widget;
);
;
])
图表设置是另一个 HTML 页面。这是我的 Draggable 指令。
更新:
我已经用Plunker
更新了问题
问题:
【问题讨论】:
我无法将指令添加到模态中.. 但您可以看到这一点。 plnkr.co/edit/cu1TVKCY8ucYcT2AScJb?p=preview 太棒了。你是怎么做到的?你对现有的做了哪些改变? 【参考方案1】:我找不到将指令添加到ui-bootstrap
打开的模态的方法,因为它用模态对话框包装了模板..
所以我所做的是使用以下代码将拖动事件设置到模态对话框本身(而不是指令)。
我知道将事件添加到指令内的另一个元素不是最佳做法,但在无法直接为元素设置指令的情况下也不是坏做法。
这样做的原因是因为ui-bootstrap 没有提供向modal.open
函数上的modal-dialog
添加指令的方法
这是要放在指令开头的代码:
element= angular.element(document.getElementsByClassName("modal-dialog"));
还有plunkr
【讨论】:
当我在原始应用程序中尝试时,它变得透明。 为此添加一些 CSS! 该指令似乎存在很多问题。甚至模态也会自动调整大小。你能检查一下这个plunker吗?我添加了一个单独的可拖动指令,名为 modaldraggable1 plnkr.co/edit/E8PzQNyyyvnvtwwcPksJ?p=preview 让我们continue this discussion in chat。【参考方案2】:我赞成@Naeem_Shaikh 的回答,这基本上是对标准角度指令的改进。
但是,我已经能够修复标准 angular draggable 指令的另一个问题。
标准指令对整个对话框施加了可拖动性。一方面,这是我们想要的。我们要拖动整个对话框。但这有一个不幸的副作用,即在对话框中的各种编辑字段中单击不起作用:默认行为被阻止!不知何故,按钮已经在引导程序中被编码来克服这个问题,但不是文本编辑字段。我猜作者没有考虑我的用例。但对话框不仅仅是按钮!
这很棘手,因为需要拖动整个对话框,但您只希望通过单击标题“热点”中的单击来启动拖动。也就是说,发起拖拽的热点是被拖拽区域的一个子集。
Naeem 的修复使我能够让它工作,这样只有在标题中单击才会启动拖动。如果没有他的修复,坐标转换就会变得混乱。
function clickedWithinHeader(event)
var target = event.currentTarget;
var hotspot = null;
var hotspots = target.getElementsByClassName("modal-header");
if (hotspots.length > 0)
hotspot = hotspots.item(0);
if (hotspot !== null)
var eY = event.clientY;
var tOT = target.offsetTop;
var y = eY - tOT;
var hH = hotspot.offsetHeight;
// since the header occupies the full width across the top
// no need to check X. Note that this assumes the header
// is on the top, which should be a safe assumption
var within = (y <= hH);
return within;
else
return true;
// Draggable directive from: http://docs.angularjs.org/guide/compiler
// Modified so that only clicks in the dialog header trigger drag behavior.
// Otherwise clicking on dialog widgets did not give them focus.
angular.module('drag', []).directive('draggable', function($document)
"use strict";
return function(scope, element)
var startX = 0, startY = 0, x = 0, y = 0;
element= angular.element(document.getElementsByClassName("modal-dialog"));
element.css(
position : 'fixed',
cursor : 'move',
);
element.on('mousedown', function(event)
// // OK, where did they touch? Only want to do this
// // when they clicked on the header.
if (!clickedWithinHeader(event))
return;
// Prevent default dragging of selected content
event.preventDefault();
...
请注意,clickedWithinHeader() 逻辑仅适用于 Naeem 的改进。 可能有更好的方法来做到这一点,但这是可行的。只有在标题中点击才会开始拖动,而在其他地方点击会做他们应该做的事情。
但是,这并不是全部答案,因为标准指令还将移动光标强加在整个对话框上,这非常令人不安,即使,或者特别是如果您无法拖动它出现的位置。
从指令中的 element.css 中删除它:
element.css(
position : 'fixed',
);
并使用 CSS 将移动光标仅绑定到模态标题
.modal-header
cursor: move;
提供完整的解决方案。
【讨论】:
【参考方案3】:我在这里合并了各种代码片段,并提出了一个更简单的解决方案。这个不依赖于检测点击事件是否发生在 modal-header 中,因为 mousedown 事件是专门绑定到 header 的。
此解决方案也不依赖于在整个 DOM 中搜索 modal-dialog 类,因为它在父级中搜索 modal-dialog 元素。这将允许您在屏幕上有多个对话框,并且只有一个是可拖动的。
我还创建了一个gist,该gist 进行了检查以防止对话框被移出可见范围。
(function (angular)
"use strict";
angular.module('MyModule')
.directive('modalDraggable', ['$document', modalDraggable]);
function modalDraggable($document)
return function (scope, element)
var startX = 0,
startY = 0,
x = 0,
y = 0;
var draggable = angular.element(element.parents('.modal-dialog')[0]);
draggable.find('.modal-header')
.css('cursor', 'move')
.on('mousedown', function (event)
// Prevent default dragging of selected content
event.preventDefault();
startX = event.screenX - x;
startY = event.screenY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
);
function mousemove(event)
y = event.screenY - startY;
x = event.screenX - startX;
draggable.css(
top: y + 'px',
left: x + 'px'
);
function mouseup()
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
;
(window.angular));
【讨论】:
【参考方案4】:我将现有解决方案更改为屏幕上的多个模式。
HTML: ……
或
... // 模态页眉、正文、页脚。JS调用模态: var modalInstance = $uibModal.open( 动画:真的, 控制器:'ModalAndamentoController', 控制器作为:'vm', windowClass: '中心模式', 尺寸:'lg', 模板网址:'modalAndamento.html' );
指令JS: (功能 () '使用严格';
角度 .module('app') .directive('draggable', draggableDirective);
/** @ngInject */ 函数 draggableDirective($document)
//busca pelo elemento
var serachElement = function (parentElement, element)
//se o elemento pai corrente é igual ao elemento, então este foi encontrado
if (parentElement == element[0])
return true;
//aprofunda mais um nível na árvore procurando pelo elemento
var i = 0;
for (i = 0; i < parentElement.childNodes.length; i++)
return serachElement(parentElement.childNodes[i], element);
return false;
;
//recupera o elemento referente ao dialog
var getDialogFromElement = function (element)
//recupera todos os dialogs da tela
var dialogs = document.getElementsByClassName("modal-dialog")
//se tiver apenas um, então esse é o dialog procurado e o mesmo é retornado
if (dialogs.length == 1)
return angular.element(dialogs[0]);
//senão, varre todos os dialogs, procurando por aquele que contém o elemento corrente na sua árvore de elementos
var i = 0;
for (i = 0; i < dialogs.length; i++)
//se encontrar o elemento correte, então esse é o dialog procurado
if (serachElement(dialogs[i], element))
return angular.element(dialogs[i]);
;
//movimenta o dialog correspondente ao elemento informado (element)
//O elemento que chega aqui é aquele que contém o atributo draggable
return function (scope, element)
var startX = 0,
startY = 0,
x = 0,
y = 0;
//recupera o dialog correspondente ao element corrente
element = getDialogFromElement(element);
//coloca o cursor de movimento no header
var header = angular.element(document.getElementsByClassName("modal-header"));
header.css(
cursor: 'move'
);
element.on('mousedown', function (event)
// Prevent default dragging of selected content
//event.preventDefault();
startX = event.screenX - x;
startY = event.screenY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
);
function mousemove(event)
y = event.screenY - startY;
x = event.screenX - startX;
element.css(
top: y + 'px',
left: x + 'px'
);
function mouseup()
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
;
)();
【讨论】:
以上是关于如何使用 angularJS 将可拖动指令应用于引导模式?的主要内容,如果未能解决你的问题,请参考以下文章