[英]best practice for integration of jquery plugin into durandal knockout SPA
我是杜蘭特和淘汰賽的新手。 我最近開始了一個使用VS2013熱毛巾模板的項目。 原來代碼有些過時了,我已經解決了一些最初的入門問題。 我正在嘗試集成與導航菜單相關的jquery插件。 但是,我無法通過shell.html視圖中的nav菜單來連接插件功能。
這是我的main.js文件:
requirejs.config({
paths: {
'text': '../scripts/vendor/require/text',
'durandal': '../scripts/vendor/durandal/js',
'plugins': '../scripts/vendor/durandal/js/plugins',
'transitions': '../scripts/vendor/durandal/js/transitions',
'knockout': '../scripts/vendor/knockout/knockout-3.1.0',
'bootstrap': '../scripts/vendor/bootstrap/bootstrap',
'toastr': '../scripts/vendor/toastr/toastr',
'jquery': '../scripts/vendor/jquery/jquery-2.1.4',
'logger': 'services/logger',
'theme' : '../scripts/js/idealTheme',
'global' : '../scripts/js/functions'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
},
'toastr': {
deps: ['jquery'],
exports: 'jQuery'
},
'theme': {
deps: ['jquery'],
exports: 'jQuery'
}
,
'global': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'plugins/router', 'logger'], function (system, app, viewLocator, router, logger) {
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.title = 'TestApp';
app.configurePlugins({
router: true,
dialog: true
});
app.start().then(function () {
//Replace 'viewmodels' in the moduleId with 'views' to locate the view.
//Look for partial views in a 'views' folder in the root.
viewLocator.useConvention();
//Show the app by setting the root view model for our application with a transition.
app.setRoot('viewmodels/shell', 'entrance');
// override bad route behavior to write to
// console log and show error toast
router.handleInvalidRoute = function (route, params) {
logger.logError('No route found', route, 'main', true);
};
});
});
和我的shell.js
define(['durandal/system',
'plugins/router',
'durandal/app',
'toastr',
'theme',
'logger'
],
function (system, router, app, toastr, theme, logger) {
var vm = this;
var router = router;
var search = function () {
toastr.info('Search is not yet implemented...');
//app.showMessage('Search not yet implemented...');
};
var activate = function activate() {
$("#nav_menu").idealtheme();
logger.log('Loaded!', null, system.getModuleId(vm), true);
}
vm = {
router: router,
showSubMenu: showSubMenu,
search: search,
activate: activate
}
return vm;
});
我的shell.html的相關部分
<div id="main_wrapper">
<header id="site_header">
<!-- End Top Search -->
<nav id="main_nav">
<div id="nav_menu">
<span class="mobile_menu_trigger">
<a href="#" class="nav_trigger"><span></span></a>
</span>
<ul id="navy" class="clearfix" >
<li class="normal_menu mobile_menu_toggle current_page_item">
<a href="index.html"><span>Home</span></a>
<ul>
<li class="normal_menu"><a href="index.html">Home Page V1</a></li>
<li class="normal_menu"><a href="index2.html">Home Page V2</a></li>
<li class="normal_menu"><a href="index3.html">Home Page V3</a></li>
<li class="normal_menu"><a href="index4.html">Home Page V4</a></li>
<li class="normal_menu"><a href="index5.html">Home Page V5</a></li>
<li class="normal_menu">
<a href="index-one-page1.html">Home One Page </a>
<ul>
<li class="normal_menu"><a href="index-one-page1.html">Home One Page V1</a></li>
<li class="normal_menu"><a href="index-one-page2.html">Home One Page V2</a></li>
</ul>
</li>
最后,主題插件文件
(function ($) {
//========> Menu
$.fn.idealtheme = function (options) {
var whatTheLastWidth = getScreenWidth();
var ifisdescktop = false;
var MqL = 1170;
var settings = {
duration: 300,
delayOpen: 0,
menuType: "horizontal", // horizontal - vertical
position: "right", // right - left
parentArrow: true,
hideClickOut: true,
submenuTrigger: "hover",
backText: "Back to ",
clickToltipText: "Click",
};
$.extend(settings, options);
var nav_con = $(this);
var $nav_con_parent = nav_con.parent("#main_nav");
var menu = $(this).find('#navy');
//=====> Mega Menu Top Space
function megaMenuTop() {
$(menu).find('.has_mega_menu').each(function () {
var top_space = $(this).parent('li').outerHeight();
$(this).find(' > .mega_menu').css({ "top": top_space + "px", "width": "100%" });
});
}
megaMenuTop();
//=====> Vertical and Horizontal
if (settings.menuType == "vertical") {
$(menu).addClass("vertical_menu");
if (settings.position == "right") {
$(menu).addClass("position_right");
} else {
$(menu).addClass("position_left");
}
} else {
$(menu).addClass("horizontal_menu");
}
//=====> Add Arrows To Parent li
if (settings.parentArrow === true) {
$(menu).find("li.normal_menu li, li.has_image_menu").each(function () {
if ($(this).children("ul").length > 0) {
$(this).children("a").append("<span class='parent_arrow normal_menu_arrow'></span>");
}
});
$(menu).find("ul.mega_menu li ul li, .tab_menu_list > li").each(function () {
if ($(this).children("ul").length > 0) {
$(this).children("a").append("<span class='parent_arrow mega_arrow'></span>");
}
});
}
function TopSearchFunc() {
$(".top_search").each(function (index, element) {
var top_search = $(this);
top_search.submit(function (event) {
event.stopPropagation();
if (top_search.hasClass("small_top_search")) {
top_search.removeClass("small_top_search");
top_search.addClass("large_top_search");
if (getScreenWidth() <= 315) {
top_search.siblings("#top_cart").animate({ opacity: 0 });
}
top_search.siblings("#nav_menu:not(.mobile_menu), .logo_container").animate({ opacity: 0 });
return false;
}
});
$(top_search).on("click touchstart", function (e) {
e.stopPropagation();
});
$(document).on("click touchstart", function (e) {
if (top_search.hasClass("large_top_search")) {
top_search.removeClass("large_top_search");
top_search.addClass("small_top_search");
if (getScreenWidth() <= 315) {
top_search.siblings("#top_cart").animate({ opacity: 1 });
}
top_search.siblings("#nav_menu:not(.mobile_menu), .logo_container").animate({ opacity: 1 });
}
});
});
if (getScreenWidth() < 1190) {
$("#navigation_bar").find(".top_search").addClass("small_top_search");
} else {
$("#navigation_bar").find(".top_search").removeClass("small_top_search");
}
}
var top_search_func = new TopSearchFunc();
$(window).resize(function () {
top_search_func = new TopSearchFunc();
megaMenuTop();
if (whatTheLastWidth > 992 && getScreenWidth() <= 992 && $("body").hasClass("header_on_side")) {
$(menu).slideUp();
}
if (whatTheLastWidth <= 992 && getScreenWidth() > 992 && $("body").hasClass("header_on_side")) {
$(menu).slideDown();
}
if (whatTheLastWidth <= 992 && getScreenWidth() > 992 && !$("body").hasClass("header_on_side")) {
resizeTabsMenu();
removeTrigger();
playMenuEvents();
}
if (whatTheLastWidth > 992 && getScreenWidth() <= 992) {
releaseTrigger();
playMobileEvents();
resizeTabsMenu();
$(menu).slideUp();
}
whatTheLastWidth = getScreenWidth();
return false;
});
//======> After Refresh
function ActionAfterRefresh() {
if (getScreenWidth() <= 992 || $("body").hasClass("header_on_side")) {
releaseTrigger();
playMobileEvents();
resizeTabsMenu();
} else {
resizeTabsMenu();
removeTrigger();
playMenuEvents();
}
}
var action_after_ref = new ActionAfterRefresh();
//======> Mobile Menu
function playMobileEvents() {
$(".nav_trigger").removeClass("nav-is-visible");
$(menu).find("li, a").unbind();
if ($(nav_con).hasClass("mobile_menu")) {
$(nav_con).find("li.normal_menu").each(function () {
if ($(this).children("ul").length > 0) {
$(this).children("a").not(':has(.parent_arrow)').append("<span class='parent_arrow normal_menu_arrow'></span>");
}
});
}
megaMenuEvents();
$(menu).find("li:not(.has-children):not(.go-back)").each(function () {
$(this).removeClass("opened_menu");
if ($(this).children("ul").length > 0) {
var $li_li_li = $(this);
$(this).children("a").on("click", function (event) {
var curr_act = $(this);
if (!$(this).parent().hasClass("opened_menu")) {
$(this).parent().addClass("opened_menu");
$(this).parent().siblings("li").removeClass("opened_menu");
if ($(this).parent().hasClass("tab_menu_item")) {
$(this).parent().addClass("active");
$(this).parent().siblings("li").removeClass("active");
}
$(this).siblings("ul").slideDown(settings.duration);
$(this).parent("li").siblings("li").children("ul").slideUp(settings.duration);
setTimeout(function () {
var curr_position = curr_act.offset().top;
$('body,html').animate({
//scrollTop: curr_position ,
}, { queue: false, duration: 900, easing: "easeInOutExpo" }
);
}, settings.duration);
return false;
}
else {
$(this).parent().removeClass("opened_menu");
$(this).siblings("ul").slideUp(settings.duration);
if ($li_li_li.hasClass("mobile_menu_toggle") || $li_li_li.hasClass("tab_menu_item")) {
return false;
}
}
});
}
});
}
function megaMenuEvents() {
$(menu).find('li.has_mega_menu ul').removeClass("moves-out");
$(menu).find('.go-back, .mega_toltip').remove();
$(menu).find('li.has_mega_menu > ul').hover(function () {
$(this).find(".mega_menu_in ul").each(function (index, element) {
var $mega_ul = $(this);
var its_height = 0;
$mega_ul.children('li').each(function (index, element) {
var ul_li_num = $(this).innerHeight();
its_height += ul_li_num;
});
$mega_ul.attr("data-height", its_height);
});
});
$(menu).find('ul.mega_menu li li').each(function (index, element) {
var $mega_element = $(this);
if ($mega_element.children('ul').length > 0) {
$mega_element.addClass("has-children");
$mega_element.children('ul').addClass("is-hidden");
}
});
$(menu).find('ul.mega_menu li.has-children').children('ul').each(function (index, element) {
var $mega_ul = $(this);
var its_height = 0;
$mega_ul.children('li').each(function (index, element) {
var ul_li_num = $(this).innerHeight();
its_height += ul_li_num;
});
$mega_ul.attr("data-height", its_height);
var $mega_link = $mega_ul.parent('li').children('a');
var $mega_title = $mega_ul.parent('li').children('a').text();
$("<span class='mega_toltip'>" + settings.clickToltipText + "</span>").prependTo($mega_link);
if (!$mega_link.find('.go-back').length) {
$("<li class='go-back'><a href='#'>" + settings.backText + $mega_title + "</a></li>").prependTo($mega_ul);
}
});
$(menu).find('ul.mega_menu li.has-children').children('a').on('click', function (event) {
event.preventDefault();
var selected = $(this);
if (selected.next('ul').hasClass('is-hidden')) {
var ul_height = parseInt(selected.next('ul').attr("data-height"));
var link_height = parseInt(selected.innerHeight());
var all_height = ul_height + link_height;
selected.addClass('selected').next('ul').removeClass('is-hidden').end().parent('.has-children').parent('ul').addClass('moves-out');
selected.closest('.mega_menu_in').animate({ height: all_height });
selected.parent('.has-children').siblings('.has-children').children('ul').addClass('is-hidden').end().children('a').removeClass('selected');
//====> if is mobile
if (selected.closest('#nav_menu').hasClass("mobile_menu")) {
selected.parent('.has-children').removeClass("mega_parent_hidden").prevAll('li').slideUp(settings.duration);
}
}
});
//submenu items - go back link
$('.go-back').on('click', function () {
var link_height = parseInt($(this).parent("ul").parent("li").parent("ul").attr("data-height"));
$(this).parent('ul').addClass('is-hidden').parent('.has-children').parent('ul').removeClass('moves-out');
$(this).closest('.mega_menu_in').animate({ height: link_height });
//====> if is mobile
if ($(this).closest('#nav_menu').hasClass("mobile_menu")) {
$(this).parent('ul').parent('li').removeClass("mega_parent_hidden").prevAll('li').slideDown(settings.duration);
}
return false;
});
}
//======> Desktop Menu
function playMenuEvents() {
$(menu).children('li').children('ul').hide(0);
$(menu).find("li, a").unbind();
$(menu).slideDown(settings.duration);
$(menu).find('ul.tab_menu_list').each(function (index, element) {
var tab_link = $(this).children('li').children('a');
$("<span class='mega_toltip'>" + settings.clickToltipText + "</span>").prependTo(tab_link);
$(this).children('li').on('mouseover', function () {
if (!$(this).hasClass('active')) {
$(this).children('ul').stop().fadeIn();
$(this).siblings().children('ul').stop().fadeOut();
$(this).addClass('active');
$(this).siblings().removeClass('active');
}
});
});
megaMenuEvents();
$(menu).find('li.normal_menu, > li').hover(function () {
var li_link = $(this).children('a');
$(this).children('ul').stop().fadeIn(settings.duration);
}, function () {
$(this).children('ul').stop().fadeOut(settings.duration);
});
}
//======> Trigger Button Mobile Menu
function releaseTrigger() {
$(nav_con).find(".nav_trigger").unbind();
$(nav_con).addClass('mobile_menu');
$nav_con_parent.addClass('has_mobile_menu');
$(nav_con).find('.nav_trigger').each(function (index, element) {
var $trigger_mob = $(this);
$trigger_mob.on('click touchstart', function (e) {
e.preventDefault();
if ($(this).hasClass('nav-is-visible')) {
$(this).removeClass('nav-is-visible');
$(menu).slideUp(settings.duration);
} else {
$(this).addClass('nav-is-visible');
$(document).unbind("click");
$(document).unbind("touchstart");
$(menu).slideDown(settings.duration, function () {
$(menu).on("click touchstart", function (event) {
event.stopPropagation();
});
$(document).on('click touchstart', function (event) {
if ($trigger_mob.hasClass('nav-is-visible') && getScreenWidth() <= 992) {
$trigger_mob.removeClass('nav-is-visible');
$(menu).slideUp(settings.duration);
}
});
});
}
});
});
}
//=====> get tabs menu height
function resizeTabsMenu() {
function thisHeight() {
return $(this).outerHeight();
}
$.fn.sandbox = function (fn) {
var element = $(this).clone(), result;
element.css({ visibility: 'hidden', display: 'block' }).insertAfter(this);
element.attr('style', element.attr('style').replace('block', 'block !important'));
var thisULMax = Math.max.apply(Math, $(element).find("ul:not(.image_menu)").map(thisHeight));
result = fn.apply(element);
element.remove();
return thisULMax;
};
$(".tab_menu").each(function () {
$(this).css({ "height": "inherit" });
if (!$(nav_con).hasClass("mobile_menu")) {
var height = $(this).sandbox(function () { return this.height(); });
$(this).height(height);
}
});
}
resizeTabsMenu();
//=====> End get tabs menu height
function removeTrigger() {
$(nav_con).removeClass('mobile_menu');
$nav_con_parent.removeClass('has_mobile_menu');
}
//----------> sticky menu
enar_sticky();
function getScreenWidth() {
return document.documentElement.clientWidth || document.body.clientWidth || window.innerWidth;
}
//----------> sticky menu
function enar_sticky() {
if ($.isFunction($.fn.sticky)) {
var $navigation_bar = $("#navigation_bar");
$navigation_bar.unstick();
var mobile_menu_len = $navigation_bar.find(".mobile_menu").length;
var side_header = $(".header_on_side").length;
if (mobile_menu_len === 0 && side_header === 0) {
$navigation_bar.sticky({
topSpacing: 0,
className: "sticky_menu",
getWidthFrom: "body"
});
} else {
$navigation_bar.unstick();
}
}
}
};
})( jQuery );
我基本上是想讓插件功能與durandal和淘汰賽一起使用。 我試圖將主題函數掛接到視圖模型中的DOM元素上,但沒有成功。 我還嘗試僅將顯示子菜單所需的代碼行放置在視圖模型中,但也沒有成功。
我嘗試創建一個函數來處理將鼠標懸停在列表項元素上的事件並顯示子菜單而沒有成功。 我收到一條錯誤消息,即未定義“兒童”功能。 我真的很想讓整個插件正常工作,但是要花些時間才能完成。
var showSubMenu = function (data, event) {
$parent = event.currentTarget;
$parent.children('ul').stop().fadeIn();
};
然后在我的shell.html中附加一個事件綁定,如下所示:
<li data-bind="event: { mouseover: showSubMenu }" class="normal_menu mobile_menu_toggle current_page_item">
我們可以提供任何信息或幫助。
謝謝,
選項1您可以將插件包裝在這樣的定義中:
define('idealtheme', ['jquery'], function($){
// idealtheme script goes here
return $;// return the jquery object, you don't really have to return anything
}
然后在我的shell中,我將“需要”該插件,它將檢測到需要jquery並先下載該插件,然后在durandal組合發生之前運行您的插件腳本:
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'plugins/router', 'logger', 'idealtheme'], function (system, app, viewLocator, router, logger, $) {
// your startup logic
選項2或者,您可以只將jQuery和其他依賴項打包為requirejs模塊打包到html文件中,而無需requirejs,例如:
<script type="text/javascript" src="~/scripts/vendor/jquery-2.1.4.js"></script>
<script type="text/javascript" src="~/scripts/vendor/knockout-3.1.0.js"></script>
<script type="text/javascript" src="~/scripts/vendor/bootstrap.js"></script>
<script type="text/javascript" src="~/scripts/js/idealtheme.js"></script>
<script type="text/javascript" src="~/scripts/vendor/toastr.js"></script>
<script type="text/javascript" src="~/scripts/js/functions.js"></script>
<script type="text/javascript" src="~/scripts/vendor/require.js" data-main="main"></script>
在main.js文件中,更改requirejs配置,刪除您現在已包含為腳本標記的路徑,並刪除shim設置,如下所示:
requirejs.config({
paths: {
'text': '../scripts/vendor/require/text',
'durandal': '../scripts/vendor/durandal/js',
'plugins': '../scripts/vendor/durandal/js/plugins',
'transitions': '../scripts/vendor/durandal/js/transitions',
'logger': 'services/logger'
}
});
然后,在仍位於main.js文件中的同時,定義將返回您剛從requirejs配置中從“路徑”中刪除的模塊的內容的模塊,如下所示:
define('jquery', function(){ return jQuery;});
define('toastr', function(){ return toastr;});
最后,繼續操作:
define(['durandal/system', 'durandal/app', 'durandal/viewLocator', 'plugins/router', 'logger'], function (system, app, viewLocator, router, logger) {
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.title = 'TestApp';
app.configurePlugins({
router: true,
dialog: true
});
app.start().then(function () {
//Replace 'viewmodels' in the moduleId with 'views' to locate the view.
//Look for partial views in a 'views' folder in the root.
viewLocator.useConvention();
//Show the app by setting the root view model for our application with a transition.
app.setRoot('viewmodels/shell', 'entrance');
// override bad route behavior to write to
// console log and show error toast
router.handleInvalidRoute = function (route, params) {
logger.logError('No route found', route, 'main', true);
};
});
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.