Javascript.RU

10 лучших функций на JavaScript

Переписанный вариант статьи Дастина Диаза

Если бы существовал универсальный файл common.js, которым пользовались бы все разработчики, вы бы нашли там эти десять (плюс одна бонусная) функций.

UPDATE март 2010: Эта статья была обновлена и переписана, чтобы соответствовать сегодняшнему дню и общему уровню сайта.

Эти функции неоднократно были испытаны и доказали свою полезность всем тем, кто их использовал. Поэтому, без лишних вступлений, вот список из десяти, по моему мнению, величайших пользовательских функций на JavaScript, которые используются в настоящее время.

Современные яваскрипт-фреймворки, конечно же, умеют все эти функции. Но иногда нужно сделать что-то без фреймворка. По разным причинам. Для этого и предназначен данный сборник полезных функций

Несомненно, важнейший инструмент в управлении событиями! Вне зависимости от того, какой версией вы пользуетесь и кем она написана, она делает то, что написано у неё в названии: присоединяет к элементу обработчик события.

function addEvent(elem, evType, fn) {
	if (elem.addEventListener) {
		elem.addEventListener(evType, fn, false);
	}
	else if (elem.attachEvent) {
		elem.attachEvent('on' + evType, fn)
	}
	else {
		elem['on' + evType] = fn
	}
}

Этот код обладает двумя достоинствами - он простой и кросс-браузерный.

Основной его недостаток - в том, он не передает this в обработчик для IE. Точнее, этого не делает attachEvent.

Для передачи правильного this можно заменить соответствующую строку addEvent на:

elem.attachEvent("on"+evType, function() { fn.apply(elem) })

Это решит проблему с передачей this, но обработчик никак нельзя будет снять, т.к. detachEvent должен вызывать в точности ту функцию, которая была передана attachEvent.

Существует два варианта обхода проблемы:

  1. Возвращать функцию, использованную для назначения обработчика:
    function addEvent(elem, evType, fn) {
    	if (elem.addEventListener) {
    		elem.addEventListener(evType, fn, false)
                    return fn
    	}
    
            iefn = function() { fn.call(elem) } 
            elem.attachEvent('on' + evType, iefn)
    	return iefn
    }
    
    function removeEvent(elem, evType, fn) {
    	if (elem.addEventListener) {
    		elem.removeEventListener(evType, fn, false)
                    return
    	}
     
            elem.detachEvent('on' + evType, fn)
    }
    

    Используется так:

    function handler() { 
        alert(this) 
    }
    var fn = addEvent(elem, "click", handler)
    ...
    removeEvent(elem, "click", fn)
    
  2. Можно не использовать this в обработчике события вообще, а передавать элемент через замыкание:

    function handler() { 
       // используем не this, а переменную, ссылающуюся на элемент
        alert(*!*elem*/!*) 
    }
    ...
    

В качестве альтернативы и для примера более серьезной библиотеки обработки событий вы можете рассмотреть статью Кросс-браузерное добавление и обработка событий.

Для инициализации страницы исторически использовалось событие window.onload, которое срабатывает после полной загрузки страницы и всех объектов на ней: счетчиков, картинок и т.п.

Событие onDOMContentLoaded - гораздо лучший выбор в 99% случаев. Это событие срабатывает, как только готов DOM документ, до загрузки картинок и других не влияющих на структуру документа объектов.

Это очень удобно, т.к. картинки могут загружаться долго, а обработчик onDOMContentLoaded может произвести необходимые изменения на странице и инициализацию интерфейсов тут же, не дожидаясь загрузки всего.

Для добавления обработчика можно использовать следующий кроссбраузерный код:

function bindReady(handler){

	var called = false

	function ready() { // (1)
		if (called) return
		called = true
		handler()
	}

	if ( document.addEventListener ) { // (2)
		document.addEventListener( "DOMContentLoaded", function(){
			ready()
		}, false )
	} else if ( document.attachEvent ) {  // (3)

		// (3.1)
		if ( document.documentElement.doScroll && window == window.top ) {
			function tryScroll(){
				if (called) return
				if (!document.body) return
				try {
					document.documentElement.doScroll("left")
					ready()
				} catch(e) {
					setTimeout(tryScroll, 0)
				}
			}
			tryScroll()
		}

		// (3.2)
		document.attachEvent("onreadystatechange", function(){

			if ( document.readyState === "complete" ) {
				ready()
			}
		})
	}

	// (4)
    if (window.addEventListener)
        window.addEventListener('load', ready, false)
    else if (window.attachEvent)
        window.attachEvent('onload', ready)
    /*  else  // (4.1)
        window.onload=ready
	*/
}
readyList = []

function onReady(handler) {

	if (!readyList.length) {
		bindReady(function() {
			for(var i=0; i<readyList.length; i++) {
				readyList[i]()
			}
		})
	}

	readyList.push(handler)
}

Использование:

onReady(function() {
  // ... 
})

Подробное описание функций bindReady, onReady и принципы их работы вы можете почерпнуть в статье Кроссбраузерное событие onDOMContentLoaded.

Изначально не написана никем конкретно. Многие разработчики писали свои собственные версии и ничья не показала себя лучше остальных.

Следующая функция использует встроенный метод getElementsByClass, если он есть, и ищет элементы самостоятельно в тех браузерах, где этого метода нет.

if(document.getElementsByClassName) {

	getElementsByClass = function(classList, node) {    
		return (node || document).getElementsByClassName(classList)
	}

} else {

	getElementsByClass = function(classList, node) {			
		var node = node || document,
		list = node.getElementsByTagName('*'), 
		length = list.length,  
		classArray = classList.split(/\s+/), 
		classes = classArray.length, 
		result = [], i,j
		for(i = 0; i < length; i++) {
			for(j = 0; j < classes; j++)  {
				if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
					result.push(list[i])
					break
				}
			}
		}
	
		return result
	}
}
classList
Список классов, разделенный пробелами, элементы с которыми нужно искать.
node
Контекст поиска, внутри какого узла искать

Например:

var div = document.getElementById("mydiv")
elements = getElementsByClass('class1 class2', div)

Следующие две функции добавляют и удаляют класс DOM элемента.

function addClass(o, c){
    var re = new RegExp("(^|\\s)" + c + "(\\s|$)", "g")
    if (re.test(o.className)) return
    o.className = (o.className + " " + c).replace(/\s+/g, " ").replace(/(^ | $)/g, "")
}
 
function removeClass(o, c){
    var re = new RegExp("(^|\\s)" + c + "(\\s|$)", "g")
    o.className = o.className.replace(re, "$1").replace(/\s+/g, " ").replace(/(^ | $)/g, "")
}

Если быть честным, наверное для этой функции существует больше различных вариантов, чем было бы нужно.

Этот вариант никоим образом он не претендует на звание универсальной функции-"переключателя", но он выполняет основную функциональность показывания и спрятывания.

function toggle(el) {
    el.style.display = (el.style.display == 'none') ? '' : 'none'
}

Обратите внимание, в функции нет ни слова про display='block', вместо этого используется пустое значение display=''. Пустое значение означает сброс свойства, т.е. свойство возвращается к значению, указанному в CSS.

Таким образом, если значение display для данного элемента, взятое из CSS - none (элемент спрятан по умолчанию), то эта функция toggle не будет работать.

Этот вариант функции toggle красив и прост, однако этот и некоторые другие недостатки делают его недостаточно универсальным. Более правильный вариант toggle, а также функции show и hide описаны в статье Правильные show/hide/toggle.

Как и getElementsByClass, этой функции почему-то нет в стандарте DOM. Возможно, чтобы избежать дублирования функционала, т.к. insertAfter реализуется всего одной строчкой.

function insertAfter(parent, node, referenceNode) {
	parent.insertBefore(node, referenceNode.nextSibling);
}

Очень жаль, что это не часть встроенной функциональности DOM. Зато теперь у нас есть возможность всё время вставлять такие вот замечания!

Для поиска эта функция использует проверку ===, которая осуществляет поиск по точному сравнению, без приведения типов.

Метод Array.prototype.indexOf поддерживается не во всех браузерах, поэтому используется, если существует.

inArray = Array.prototype.indexOf ?
    function (arr, val) {
        return arr.indexOf(val) != -1
    } :
    function (arr, val) {
        var i = arr.length
        while (i--) {
            if (arr[i] === val) return true
        }
        return false
    }

В javascript нет способа нормально работать с cookie без дополнительных функций. Не знаю, кто проектировал document.cookie, но сделано на редкость убого.

Поэтому следующие функции или их аналоги просто необходимы.

// возвращает cookie если есть или undefined
function getCookie(name) {
	var matches = document.cookie.match(new RegExp(
	  "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
	))
	return matches ? decodeURIComponent(matches[1]) : undefined 
}

// уcтанавливает cookie
function setCookie(name, value, props) {
	props = props || {}
	var exp = props.expires
	if (typeof exp == "number" && exp) {
		var d = new Date()
		d.setTime(d.getTime() + exp*1000)
		exp = props.expires = d
	}
	if(exp && exp.toUTCString) { props.expires = exp.toUTCString() }

	value = encodeURIComponent(value)
	var updatedCookie = name + "=" + value
	for(var propName in props){
		updatedCookie += "; " + propName
		var propValue = props[propName]
		if(propValue !== true){ updatedCookie += "=" + propValue }
	}
	document.cookie = updatedCookie

}

// удаляет cookie
function deleteCookie(name) {
	setCookie(name, null, { expires: -1 })
}

Аргументы:

name
название cookie
value
значение cookie (строка)
props
Объект с дополнительными свойствами для установки cookie:

expires
Время истечения cookie. Интерпретируется по-разному, в зависимости от типа:

  • Если число - количество секунд до истечения.
  • Если объект типа Date - точная дата истечения.
  • Если expires в прошлом, то cookie будет удалено.
  • Если expires отсутствует или равно 0, то cookie будет установлено как сессионное и исчезнет при закрытии браузера.
path
Путь для cookie.
domain
Домен для cookie.
secure
Пересылать cookie только по защищенному соединению.

Она позволяет функции работать одинаково при передаче DOM-узла или его id.

function byId(node) {
        return typeof node == 'string' ? document.getElementById(node) : node
}

Используется просто:

function hide(node) {
    node = byId(node)
    node.style.display = 'none'
}

function animateHide(node)
   node = byId(node)
   something(node)
   hide(node)
}

Здесь обе функции полиморфны, допускают и узел и его id, что довольно удобно, т.к. позволяет не делать лишних преобразований node <-> id.


Надеюсь, этот небольшой и удобный список JavaScript-функций будет столь же полезен вам, сколь он полезен мне.


Автор: Арсений (не зарегистрирован), дата: 16 февраля, 2009 - 13:03
#permalink

в JS нет худших и лучших функций, все нужны и полезны в конкретных ситуациях


Автор: Dmitris (не зарегистрирован), дата: 19 февраля, 2009 - 11:22
#permalink

Я бы еще добавил динамическую подгрузку JavaScript файлов, например этот метод: http://www.artlebedev.ru/tools/technogrette/js/include/

или метод который используется в Scriptalicous


Автор: Aleko (не зарегистрирован), дата: 8 января, 2010 - 03:40
#permalink

Не нашел куда написать, поэтому пишу сюда. Я написал самое компактное определение IE из всех которые я знаю. Думаю пригодится:

var ie=!-[1,];
alert(ie);

можно и в 5 символов, но будет возвращаться false в эксплорере

var notie=-[1,];
alert(notie);

Используется баг с подсчетом элементов массива.

Подробнее здесь: линк


Автор: Илья Кантор, дата: 11 января, 2010 - 13:18
#permalink

Статью переписал. Как следствие, многие комментарии перестали относиться к переписанному варианту и были убраны.
По виду, получилось более актуально чем было...


Автор: Бобр, дата: 21 января, 2010 - 11:14
#permalink

Функции setCookie и getCookie работают в FireFox, но не работают в Chrome:

setCookie('Test1', 'TestText1', "");
alert(getCookie('Test1'));

В чём тут дело? Либо можно пример вызова, который точно работает?


Автор: Илья Кантор, дата: 21 января, 2010 - 12:40
#permalink

Дело в том, что 3й аргумент - props - объект. Если не хотите его указывать - не надо ставить "".

setCookie('Test1', 'TestText1');
alert(getCookie('Test1'));

Автор: Бобр, дата: 21 января, 2010 - 13:49
#permalink

Так тоже не работает. У вас установлен Хром? Ну, попробуйте создать пустую страничку с одним этим скриптом. Выдаст undefined. A FireFox - "TestText1".


Автор: Илья Кантор, дата: 21 января, 2010 - 14:09
#permalink

Да, установлен. Попробуйте сами - вот страничка http://javascript.ru/test.html . Все работает.


Автор: Бобр, дата: 21 января, 2010 - 14:24
#permalink

Но я же не могу свои странички к вам на сервер закачивать. Я запускаю со своего винчестера. И не работает.


Автор: Илья Кантор, дата: 21 января, 2010 - 14:51
#permalink

Закачайте их к себе на сервер и запустите. Дело, видимо, как раз в том, что вы с винчестера запускаете, а надо - с сайта.


Автор: Бобр, дата: 21 января, 2010 - 18:24
#permalink

А у меня сейчас нету сервера. Да и неудобно это. Вот на винчестере страничка, я её правлю, и сразу проверяю в браузере, никуда не закачивая.

Да и в FireFox'e то работает нормально. Может что-то не учтено, надо в скрипт ещё какую-то строчку кода для Хрома добавить?


Автор: Гость (не зарегистрирован), дата: 23 января, 2010 - 00:34
#permalink

Насколько я знаю, кука ставиться для УРЛа (Домена).
Если вы открываете страничку с винта, то где там имя домена?
Возможно Хром понимает бесполезность такого действия и ничего не предпринимает.
Насчет сервера: почему это неудобно? Неужели трудно поставить Денвер или какой-нибудь его аналог и работать в нормальных условиях, приближенных к реальным?


Автор: Гость (не зарегистрирован), дата: 5 ноября, 2010 - 15:37
#permalink

localhost )


Автор: SergeyM (не зарегистрирован), дата: 21 марта, 2011 - 19:06
#permalink

В хроме, начиная с 5й версии локально многие вещи не работают.
Например "ajax" и cookie.

Чтобы это работало "с винчестера" нужно запускать chrome.exe с ключами (можно дописать в свойства ярлыка):
--allow-file-access-from-files --enable-file-cookies


Автор: Гость (не зарегистрирован), дата: 21 мая, 2010 - 09:25
#permalink

у хрома (по крайней мере на начальных этапах его становления и развития) наблюдается проблема с работой кук. долго бился, пока не понял это =( куки ни одним обычным методом не удалялись: и пустоту в них писал, и нулл, и время в прошлое... просто голову сломал.


Автор: smashercosmo, дата: 4 марта, 2010 - 21:57
#permalink

Объясните пожалуйста, зачем в функции getElementsByClass():
a) нужна переменная key
b) нужны границы слова в

'\\b' + classArray[j] + '\\b'

Автор: Илья Кантор, дата: 31 марта, 2010 - 02:05
#permalink

а) убрал, она лишняя была
б) границы нужны, чтобы корректно обрабатывать элемент со множеством классов:

<div class="header logo">...</div>

Автор: smashercosmo, дата: 15 апреля, 2010 - 13:49
#permalink

Без указания границ слова всё обрабатывается корректно. По крайней мере я не смог создать такую ситуацию, когда отсутствие границ слова вызвало бы ошибку. Проверял с разными классами, с разным количеством пробелов, в разных браузерах. Не могли бы вы привести пример когда без границ слова, будет выводиться что-то неправильное?


Автор: smashercosmo, дата: 21 апреля, 2010 - 13:54
#permalink

Всё. Дошло. На самом деле "\\b" нужно не для того чтобы обрабатывать элементы с несколькими классами. А для таких случаев, если у меня есть один элемент с "class1" и другой элемент с "class11111". Без "\\b" по запросу "class1" будут найдены оба элемента.


Автор: Гость (не зарегистрирован), дата: 17 мая, 2010 - 16:58
#permalink

Пожалуйста верните комментарий, в котором приведены аналоги на JQuery.
Он был очень полезным.


Автор: Гость (не зарегистрирован), дата: 2 августа, 2010 - 18:14
#permalink
for(;;){alert('-')};

Автор: GreatRash, дата: 17 августа, 2010 - 14:52
#permalink

Нашел красивейшую функцию по замене inArray:

function oc(a) {
	var o = {};
	
	for (var i = 0, l = a.length; i < l; i++) {
		o[a[i]] = '';
	}
	
	return o;
}

alert('test' in oc(['te', 'st', 'test']));
alert('test' in oc(['te', 'st', 'es', 't']));
alert(25 in oc([1, 2, 3, 4, 25]));
alert(1 in oc([2, 3, 4, 25]));

Источник


Автор: MainBuh, дата: 3 декабря, 2010 - 14:51
#permalink

Да действительно орининальное решение - но бесполезное - слишком много итераций. Это при больших массивах очень долго, особенно если искомое значение (по "закону полдлости") будет вначале масива.
Еще недостаток она не универсальна - с объектами работать не будет
("...a.length ...").

Знаю что не открываю Америку и не изобретаю велосипед - поэтому это только для GreatRash (автора комментария):

//-Проверяет содержится ли значение в массиве/объекте
inObject=inArray=function(obj, value, flEqualityType){
/*
Параметры:
- obj - объект или массив значений в котором ищем
- value - искомое значение
- flEqualityType - (необязательный) - флаг сравнения типов [true | false]
(по умолчанию false - сравнение без типов данных)
*/
var obj=obj, value=value, flEqualityType=flEqualityType || false;
if(!obj || typeof(obj)!='object') return false;
for(var i in obj){
if(flEqualityType===true && obj[i]===value) return true;
if(flEqualityType===false && obj[i]==value) return true;
}
return false;
};


Автор: blogic (не зарегистрирован), дата: 20 августа, 2010 - 22:06
#permalink

Функция insertAfter не будет работать, если попытаться вставить ноду после последнего элемента в узле, т.к. его nextSibling == null. Вот рабочий вариант:

function insertAfter(node, ref_node) {
	var next = ref_node.nextSibling;

	if (next) next.parentNode.insertBefore(node, next);
	else ref_node.parentNode.appendChild(node);
}

Можно обойтись и без дополнительной переменной next, но так наглядней...


Автор: RomanWeberov (не зарегистрирован), дата: 10 сентября, 2010 - 19:49
#permalink

Ваш пример нужно дорабатывать, т.к. nextsibling может указывать на текстовый элемент.

function next(elem) {
do {
elem = elem.nextSibling;
} while ( elem && elem.nodeType != 1 );
return elem;
}

Ну и соответственно

var next = next(ref_node);

Автор: blogic (не зарегистрирован), дата: 17 сентября, 2010 - 13:43
#permalink

RomanWeberov, с какой такой стати текстовые элементы не должны учитываться? Функция insertAfter() должна вставлять элемент строго после указанного и никак иначе.


Автор: Илья Кантор, дата: 11 сентября, 2010 - 14:41
#permalink

Вы проверяли, что не будет работать?

Относительно текстового элемента - он тоже элемент..


Автор: blogic (не зарегистрирован), дата: 17 сентября, 2010 - 14:01
#permalink

Да, надо было проверить:(
Теперь буду знать:)
Но в любом случае, функцию можно упростить, убрав из списка аргументов parent'а.


Автор: юрист (не зарегистрирован), дата: 13 октября, 2010 - 21:57
#permalink

Отличная подборка сценариев Обожаю ваш блог и ваш труд


Автор: monolithed, дата: 5 января, 2011 - 01:08
#permalink

Илья, мне кажется пример с getElementsByClassName() может ввести в заблуждение новичков, потому как этот метод по спецификации принимает один аргумент, а у тебя в примере использования их несколько причем еще и ID. Для этого есть querySelector(), querySelectorAll();

К тому же код можно упростить, сделать более универсальным, а также значительно увеличить производительность:

<script type="text/javascript">
window.onload = function() {
	getElementsByClass = function(getClass){
		if(document.querySelectorAll) {
			return document.querySelectorAll("." + getClass);
		}
		else if(document.getElementsByClassName) {
			return document.getElementsByClassName(getClass);
		}
		else {
			var list = document.getElementsByTagName('*'), i = list.length,
			classArray = getClass.split(/\s+/), result = [];
			while(i--) {
				if(list[i].className.search('\\b' + classArray + '\\b') != -1) {
					result.push(list[i]);
				}
			}
			return result;
		}
	};
	getElementsByClass('class')[0].style.color = 'red';
};
</script>
<p class="class">text</p>

PS: добавление querySelectorAll() дает нам возможность работать с IE8+, а обратный цикл уменьшает время выполнения функции в несколько раз


Автор: Илья Кантор, дата: 5 января, 2011 - 01:12
#permalink

Отличный вариант, спасибо.


Автор: Denisko-Redisko, дата: 28 августа, 2011 - 10:31
#permalink

Нельзя использовать в регулярках \bneedle\b, так как christmas-tree-needle это один класс.

<div id="d1">
<p class="par">Текстовый блок НЕ ДОЛЖЕН быть подсвечен</p>
<p class="par-tition">Текстовый блок НЕ ДОЛЖЕН быть подсвечен</p>
<p class="par par1">Текстовый блок должен быть подсвечен</p>
<p class="par asd par1 qwe">Текстовый блок должен быть подсвечен</p>
</div>
<div id="d2">
<p class="par">Текстовый блок НЕ ДОЛЖЕН быть подсвечен</p>
<p class="par-tition">Текстовый блок НЕ ДОЛЖЕН быть подсвечен</p>
<p class="par par1">Текстовый блок должен быть подсвечен</p>
<p class="par asd par1 qwe">Текстовый блок должен быть подсвечен</p>
</div>

<script type="text/javascript">
if (document.getElementsByClassName) {
    getElementsByClass = function(classList, node) {    
        return (node || document).getElementsByClassName(classList)
    }
} else {

    getElementsByClass = function(classList, node) {            
        var node = node || document,
        list = node.getElementsByTagName('*'), 
        length = list.length,
        classArray = classList.split(/\s+/), 
        classes = classArray.length, 
        result = [], i,j
        for(i = 0; i < length; i++) {
            for(j = 0; j < classes; j++)  {
                if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
                    result.push(list[i])
                    break
                }
            }
        }
        return result
    }
}

function findByClass(str, node) {

    node || (node = document);

    if (node.getElementsByClassName) {
        return node.getElementsByClassName(str);
    } else {
        var nodeList = node.getElementsByTagName('*'),
            nodeListIndex = 0,
            classList = (' '+str.split(/\s+/).join(' ; ')+' ').split(';'),
            classListIndex,
            result = [],
            className,
            index;

        while (node = nodeList[nodeListIndex++]) {
            index = 0;
            classListIndex = 0;
            while (className = classList[classListIndex++]) {
                if ((' ' + node.className + ' ').indexOf(className) >= 0) {
                    index++;
                }
            }
            if (index == classList.length) {
                result.push(node);
            }
        }
        return result;
    }
}


var elems = getElementsByClass('par par1', document.getElementById("d1"));
for (var i = 0, len = elems.length; i < len; i++) {
    elems[i].style['color'] = 'red';
}

var elems = findByClass('par par1', document.getElementById("d2"));
for (var i = 0, len = elems.length; i < len; i++) {
    elems[i].style['color'] = 'blue';
}
</script>

Автор: VitAl2013, дата: 2 апреля, 2012 - 09:44
#permalink

В FireFox 11 подсветка не работает.


Автор: chernavin.a.a (не зарегистрирован), дата: 7 февраля, 2011 - 14:44
#permalink

Функция getElementsByClass() работает неверно в IE при поиске узлов с несколькими классами.

<script type="text/javascript">
if(document.getElementsByClassName) {

	getElementsByClass = function(classList, node) {    
		return (node || document).getElementsByClassName(classList)
	}

} else {

	getElementsByClass = function(classList, node) {			
		var node = node || document,
		list = node.getElementsByTagName('*'), 
		length = list.length,  
		classArray = classList.split(/\s+/), 
		classes = classArray.length, 
		result = [], i,j
		for(i = 0; i < length; i++) {
			for(j = 0; j < classes; j++)  {
				if(list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
					result.push(list[i])
					break
				}
			}
		}
	
		return result
	}
}

		elems=getElementsByClass('par par1');
		for (var i=0;elems.length;i++)
			elems[i].style.color='red';
		</script>

<p class="par">Текстовый блок</p>
<p class="par par1">Текстовый блок под номером два</p>

В FF и Opera будет выделен второй абзац, т.к. используется встроенная функция, а IE выделит оба.


Автор: medium, дата: 2 апреля, 2011 - 18:32
#permalink

8) getElementsByClass()
Все таки не представлен настоящии универсальный метод:(
По моему самый лучшии вариант от monolithed
НО он загружает только 1 класс
Как правильно сделать полный обход?

var classl=getElementsByClass('class1').length;
for (var i=0; i<classl; i++) {
getElementsByClass('class1')[i].style.color='red';
};// пока только так придумал.. подскажите плиз


Автор: Гость (не зарегистрирован), дата: 12 апреля, 2011 - 04:41
#permalink

Я для себя написал вот такой inArray, он работает и для многомерных массивов

Array.prototype.inArray = Array.prototype.indexOf ? function(elem){
		for(var i = 0, len = this.length; i < len; i ++){
			if(this.indexOf(elem) != -1 || (this[i] instanceof Array && this[i].inArray(elem))){
				return true;
			}
		}
		return false;
	} : function(elem){
			for(var i = 0, len = this.length; i < len; i ++){
				if(elem === this[i] || (this[i] instanceof Array && this[i].inArray(elem))){
					return true;
				}
			}
			return false;
		}

Автор: poorking, дата: 12 апреля, 2011 - 05:11
#permalink

Точнее так

Array.prototype.inArray = Array.prototype.indexOf ? function(elem){
		if(this.indexOf(elem) != -1){
			return true;
		}else{
			for(var i = 0, len = this.length; i < len; i ++){
				if(this[i] instanceof Array && this[i].inArray(elem)){
					return true;
				}
			}
		}
		return false;
	} : function(elem){
			for(var i = 0, len = this.length; i < len; i ++){
				if(elem === this[i] || (this[i] instanceof Array && this[i].inArray(elem))){
					return true;
				}
			}
			return false;
		}

Автор: Гость (не зарегистрирован), дата: 16 июня, 2011 - 13:07
#permalink

Кстати я по поводу куков. Зах сервер покупать, если из своего компа сервер через cmp сделать можно.


Автор: Гость (не зарегистрирован), дата: 28 июля, 2011 - 12:27
#permalink

у


Автор: Гость (не зарегистрирован), дата: 8 октября, 2011 - 13:49
#permalink

Ошибка в inArray(), строка 8. вместо a[] надо arr[]


Автор: m4gz, дата: 1 ноября, 2011 - 19:52
#permalink
document.getElementsByClassName = function(cl) {
var retnode = [];
var myclass = new RegExp('\\b'+cl+'\\b');
var elem = this.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) retnode.push(elem[i]);
}
return retnode;
};

GET
CLASS


Автор: Гость (не зарегистрирован), дата: 21 декабря, 2011 - 12:31
#permalink

Как по мне, так такой вариант выборки классов будет побыстрее:

getElementsByClassName = function(klass, root) {
	root = root || document;
	if (root.querySelectorAll) {
		return root.querySelectorAll('.' + klass)
	} else if (root.getElementsByClassName) {
		return root.getElementsByClassName(klass)
	} else {
		var list = root.all || root.getElementsByTagName('*');
		var result = [];
		for (var index = 0,
		elem; elem = list[index++];) {
			if (elem.className && (' ' + elem.className + ' ').indexOf(' ' + klass + ' ') > -1) {
				result[result.length] = elem
			}
		}
		return result
	}
};

Автор: Гость (не зарегистрирован), дата: 16 февраля, 2012 - 17:06
#permalink


Автор: evgh, дата: 17 февраля, 2012 - 16:15
#permalink

мой вариант функции inArray
без цикла, и символов меньше


Автор: WolF™ (не зарегистрирован), дата: 31 марта, 2012 - 14:27
#permalink

А не легче использовать такой код:

document.getElementsByClassName = function (cl) {
     return document.querySelectorAll('.' + cl);
}

Или я чего-то не понимаю?


Автор: Гость (не зарегистрирован), дата: 27 августа, 2012 - 14:05
#permalink

Например, того, что некоторые недобраузеры функции querySelectorAll не понимают.


Автор: C.I.A. (Гость) (не зарегистрирован), дата: 8 сентября, 2012 - 15:48
#permalink

8) getElementsByClass()

if(document.getElementsByClassName){
 /*
 Здесь логика AND:
 getElementsByClassName - ищет строгое соответствие строке classList
 т.е. к элементу должно быть применено class1 && class2
*/
}else{
 /*
 Здесь логика OR:
 разбор строки classList
 т.е. к элементу может быть применено море классов и поиск такой
 class1 || class2
*/
}

Вариант:

if(document.getElementsByClassName){
  var getElementsByClass = function(classList, node){
  var node = node || document,
       classArray = classList.split(/\s+/),
       result=[];
  for(i=0; i<classArray.length; i++){
    j=node.getElementsByClassName(classArray[i]);
    if(j!='undefined'){
     result.push(node.getElementsByClassName(classArray[i]));
    }
  }
  return result;//aray nodes
 }
}else{
// ... для недобраузеров код прежний
}

Автор: KoVaLsKy (не зарегистрирован), дата: 19 октября, 2012 - 14:35
#permalink

Подскажите, пожалуйста setCookie(name, value, props)
как у эту функцию установить время или дату.
я так понимаю что она сидит в props
как задать в него параметры


Автор: Гость (не зарегистрирован), дата: 23 ноября, 2012 - 16:17
#permalink

подскожите пож. как из .csv где есть много строк, наити самыю длиныю строку и выведить её ,при етом показати сколько букв содержит строка и какой ряд?


Автор: Гость (не зарегистрирован), дата: 23 ноября, 2012 - 16:39
#permalink

подскожите пож. как из .csv где есть много строк, наити самыю длиныю строку и выведить её ,при етом показати сколько букв содержит строка и какой ряд?


Автор: Гость (не зарегистрирован), дата: 6 мая, 2013 - 18:51
#permalink

Предлагаю свой вариант работы с классами:

var has_class=function(obj,class_name){	return _has_class.apply(null,arguments); };
	var _has_class=function(obj,class_name){
		
		var hc1=function( obj , class_name ){ return obj.classList.contains(class_name); }
		var hc2=function( obj , class_name ){ class_name = " " + class_name + " "; return ( (' '+obj.className+' ').indexOf(class_name) >= 0 );	}
		
		if( obj.classList ){ _has_class=hc2; }else{	_has_class=hc2;	}		
		hc1=hc2=null;
		return _has_class.apply(null,arguments);
	};
	
	var add_class=function( obj , class_name ){return _add_class.apply(null,arguments); };
	var _add_class=function( obj , class_name ){
		var ac1=function( obj , class_name ){	obj.classList.add(class_name); return this;}			
		var ac2=function( obj , class_name ){
			var re = new RegExp("(^|\\s)" + class_name + "(\\s|$)", "g");
			if (!re.test(obj.className)) {obj.className = (obj.className + " " + class_name).replace(/\s+/g, " ").replace(/(^ | $)/g, "");}
		};
		
		if( obj.classList ){ _add_class=ac1; }else{ _add_class=ac2;	}
		ac1=ac2=null;
		_add_class.apply( null, arguments );
	};
	
	var remove_class=function( obj , class_name ){ return _remove_class.apply(null,arguments); };
	var _remove_class=function( obj , class_name ){
		var rc1=function( obj , class_name ){ obj.classList.remove(class_name); };			
		var rc2=function( obj , class_name ){
			var re = new RegExp("(^|\\s)" + class_name + "(\\s|$)", "g"); obj.className = obj.className.replace(re, "$1").replace(/\s+/g, " ").replace(/(^ | $)/g, "");
		}
		if( obj.classList ){_remove_class=rc1;}else{_remove_class=rc2;}
		rc1=rc2=null;
		remove_class.apply(null,arguments);
	};

Немного сжато, рабочий вариант.
Применен шаблон самоопределяемых функций.
Функции обертки нужны, чтобы иметь возможность правильно импортировать функции из области видимости.

Преимущества: определение пути выполнения осуществляется только один раз, при первом вызове функции, при этом используются возможности HTML5. Нормальные браузеры будут работать еще быстрее (чем в JQuery, но не проверял), не нормальные - на том же уровне.

Немного переживаю за излишнее замыкание, но пошел на наго из-за компактности.

Еще пара функций:

var get_offset=function(elem){ return _get_offset(elem); };
	var _get_offset=function(elem){
	
		var __getOffsetRect=function(elem) {
			var box = elem.getBoundingClientRect();
			var body = document.body;
			var docElem = document.documentElement;
			var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
			var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
			var clientTop = docElem.clientTop || body.clientTop || 0;
			var clientLeft = docElem.clientLeft || body.clientLeft || 0;
			var top  = box.top +  scrollTop - clientTop;
			var left = box.left + scrollLeft - clientLeft;
			return { top: Math.round(top), left: Math.round(left) };
		};
		
		var __getOffsetSum=function(elem) {
			var top=0, left=0;
			while(elem) {top = top + parseInt(elem.offsetTop);left = left + parseInt(elem.offsetLeft);elem = elem.offsetParent ;}
			return {top: top, left: left};
		};
	
		if (elem.getBoundingClientRect) { _get_offset=__getOffsetRect; } else { _get_offset=__getOffsetSum; }
		
		__getOffsetRect=__getOffsetSum=null;
		
		return _get_offset(elem);
	};
	
	var fix_event=function(e){ return _fix_event(e); };
	var _fix_event=function(e){
		var __fix_event_ie=function(e){	
			e = e || window.event;
			var html = document.documentElement;
			var body = document.body;
			e.pageX = e.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html.clientLeft || 0);
			e.pageY = e.clientY + (html && html.scrollTop || body && body.scrollTop || 0) - (html.clientTop || 0);
			if (e.button & 1) { e.which = 1; } else if (e.button & 4) { e.which = 2; } else if (e.button & 2) {e.which = 3;}
			e.target=e.srcElement;
			return e;
		};
		var __fix_event_html5=function(e){ return e; };
		e = e || window.event;
		if( e.pageX == null && e.clientX != null ){ _fix_event=__fix_event_ie; }else{ _fix_event=__fix_event_html5; }
		__fix_event_ie=__fix_event_html5=null;
		return _fix_event(e);
	};

Автор: psyhonaut (не зарегистрирован), дата: 8 декабря, 2013 - 20:42
#permalink

Добрый день.

Не могу разобраться с клонированием картинок при перетаскивании. Можете направить где копать?


Автор: Гость (не зарегистрирован), дата: 10 декабря, 2014 - 16:40
#permalink

addClass
Какая-то стрёмная замена classList.add()


Автор: Glor (не зарегистрирован), дата: 18 марта, 2015 - 18:18
#permalink

function insertAfter(parent, node, referenceNode) {
parent.insertBefore(node, referenceNode.nextSibling);
}

И где тут проверка, что это не младший сын?


Автор: Seitbekir (не зарегистрирован), дата: 9 сентября, 2015 - 19:13
#permalink

Эти приемы слишком не соответствуют сути прототипно-ориентированного языка.

Почему бы не myObject.addEvent?

как де queryString?

Где демонстрация работы с динамическими элементами?

Да, порой фреймворк использовать не получается (покажите мне такой, в ЛС), но это плохой подход.

ПС: Кину свою мини-библиотеку нужнрых мне порой функций.

Array.prototype.last = function(){ return this[this.length - 1]; }
Array.prototype.unique = function(){
   var u = {}, a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(u.hasOwnProperty(this[i])) {
         continue;
      }
      a.push(this[i]);
      u[this[i]] = 1;
   }
   return a;
}
Array.prototype.remove = function(i){ this.splice(i, 1); }

String.prototype.times = function(n){
	var s = '';
	for (var i = 0; i < n; i++){ s += this; }
	return s;
}
ObjLength = function(obj) { if(typeof(obj) != "object") return null; var n = 0; for(var i in obj){ n++; } return n; }
String.prototype.zp = function(n) { return '0'.times(n - this.length) + this; }
Number.prototype.zp = function(n) { return this.toString().zp(n); }
String.prototype.zt = function(n) { return this + '0'.times(n - this.length); } 
Number.prototype.zt = function(n) { return this.toString().zt(n); }

String.prototype.toInt = function() { return parseInt(this); }
String.prototype.toFloat = function() { return parseFloat(this); }
String.prototype.toNumber = function() { return parseFloat(this); }
Number.prototype.toInt = function() { return parseInt(this); }
Number.prototype.toFloat = function() { return parseFloat(this); }
Number.prototype.toNumber = function() { return parseFloat(this); }

Date.prototype.daysInMonth = function() {
	return 33 - new Date(this.getFullYear(), this.getMonth(), 33).getDate();
};

HTMLElement.prototype.remove = function(){ if(this.parentNode != null) this.parentNode.removeChild(this); else delete(this); }
HTMLElement.prototype.insertAfter = function(elem){ this.parentNode.insertBefore(elem, this.nextSibling); }
HTMLElement.prototype.replace = function(elem){ this.parentNode.insertBefore(elem, this.nextSibling); this.remove(); }

var webStore = 
{
	setItem: function (name, object)
		{
			localStorage.setItem(name, JSON.stringify(object))
		},
	getItem: function (name)
		{
			return JSON.parse(localStorage.getItem(name))
		},
	clear: function (name)
		{
			localStorage.clear()
		}
}

ПС2: Пользуйтесь jQ, Angular, polymer и все будет в порядке.


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
2 + 4 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Реклама
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum