Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   События / таймеры (https://javascript.ru/forum/events/44787-sobytiya-tajjmery.html)

Boolean_Type 02.02.2014 03:34

События / таймеры
 
Здравствуйте!
Задача: необходимо, чтобы при нажатии на кнопку меню плавно из-под неё выезжало. При повторном нажатии или нажатии НЕ на неё - так же плавно "въезжало" в неё. jQuery по опр. причинам не подходит.
Код ещё не доработан, в нём много шлака, строго его не судите:
<head>
<title> </title>
<meta charset='utf-8'>
<style>
	html, body{
		height:100%;
		margin:0;
		padding:0;
	}
	#right_menu, li{
		margin:0;
		padding:0;
		display:block;
	}
	#right_menu{
		position:absolute;
		width:65px;
		height:125px;
		background-color:#cccccc;
		border:2px solid;
		border-color: #dddddd #bbbbbb #bbbbbb #dddddd;
		padding-left:50px;
	}
	li{
		width:60px;
		height:25px;
		margin:5px;
		line-height:25px;
		font-family:arial, sans-serif;
		font-size:10pt;
		text-indent:5px;
	}
	li:hover{
		background-color:navy;
		color:white;
	}
	#b{
	position:absolute;
	top:50px;
	left:10px;
	}
	
</style>
</head>

<body>
<ul id='right_menu'>
	<li>Effect 1</li>
	<li>Effect 2</li>
	<li>Effect 3</li>
	<li>Effect 4</li>
</ul>
<input type='button' id='b' value = 'Click'>

var flag = false;

var menu=document.getElementById('right_menu');
//меню скрыто при загрузке стр-цы
menu.style.display='none';

var button = document.getElementById('b');

button.onclick=function(event){
//меню будет появл-ся там, где щёлкнули правой кнопкой
menu.style.left=parseInt(getComputedStyle(button).left)+'px';
menu.style.top=parseInt(getComputedStyle(button).top)+'px';

	
	if(flag == false){
		menu.style.display='block';
		intr_show=setInterval(show,1);
		flag = true;
	}else{
		intr_hide=setInterval(hide,1);
		document.body.onclick = setInterval(hide,1); //какой-то бред написан, но и без этой строки работает по-другому
		flag=false;
	}
}

function show(){
//показываем UL
width = parseInt(getComputedStyle(menu).width);
height = parseInt(getComputedStyle(menu).height);
if(width >= 65 && height >= 125) {return}
menu.style.width = (width + 1)+'px';
menu.style.height = (height + 1)+'px';

//показываем LI
var lis = document.querySelectorAll('li');
for(var i=0; i<lis.length;i++){
widthLi = parseInt(getComputedStyle(lis[i]).width);
heightLi = parseInt(getComputedStyle(lis[i]).height);
if (widthLi == 60 && heightLi ==25) {	
	lis[0].innerHTML = 'Effect 1';
	lis[1].innerHTML = 'Effect 2';
	lis[2].innerHTML = 'Effect 3';
	lis[3].innerHTML = 'Effect 4';
return} //чтобы ф-ция не вып-яла лишних действий
	
lis[i].style.width = (widthLi + 1)+'px';
lis[i].style.height = (heightLi + 1)+'px';
}
}
	

function hide(){
//прячем UL
widthUl = parseInt(getComputedStyle(menu).width); /*не обязат-но
глобальная, т.к. перезапись происх-ит в св-ве: menu.style.width,
а width получаем из него же*/
heightUl = parseInt(getComputedStyle(menu).height);
if (widthUl <= 0 && heightUl <=0) {
menu.style.border = 'none';
return} //чтобы ф-ция не вып-яла лишних действий
menu.style.width = (widthUl - 1)+'px';
menu.style.height = (heightUl - 1)+'px';

//прячем LI
var lis = document.querySelectorAll('li');
for(var i=0; i<lis.length;i++){
widthLi = parseInt(getComputedStyle(lis[i]).width);
heightLi = parseInt(getComputedStyle(lis[i]).height);
if (widthLi == 0 && heightLi ==0) {
/*lis[i].innerHTML = '';  не корректно, т.к. if сработает сначала для
i=0, но после "обнуления" innerHTML стоит return, кот-ый выкинет из
ф-ции. При след-ем её запуске цикл опять начнётся с 0 и return опять
выкинет после lis[0].innerHTML = ''; . Выходит, что innerHTML обнулится
лишь у 1го эл-та*/
	for(var j=0; j<lis.length;j++){
	lis[j].innerHTML = '';
	}
return} //чтобы ф-ция не вып-яла лишних действий

lis[i].style.width = (widthLi - 1)+'px';
lis[i].style.height = (heightLi - 1)+'px';
console.log(getComputedStyle(lis[i]).width)
}
}


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

ksa 02.02.2014 10:29

Цитата:

Сообщение от Boolean_Type
задание срочное. Поэтому даже не знаю, что тут можно сделать

Как вариант, предложить оплату, может кого-то это заинтересует...

kostyanet 02.02.2014 10:51

http://candpgeneration.com/toys/CSS3-dropdown-tut.php

без js

Boolean_Type 02.02.2014 15:47

Цитата:

Сообщение от ksa (Сообщение 295296)
Как вариант, предложить оплату, может кого-то это заинтересует...

:-)))
Полностью согласен)))
Да только это не от заказчика, а на курсах задали.

Boolean_Type 02.02.2014 15:50

Цитата:

Сообщение от kostyanet (Сообщение 295305)

Спасибо большое, со св-вом CSS transition знаком, но нужно именно JS.

Мне кажется, мой алгоритм в общем верен, просто из-за нехватки теор. знаний я где-то лажаю...

рони 02.02.2014 18:01

Boolean_Type,
Вариант на основе темы Дёрганье при смене анимации
<!DOCTYPE HTML>

<html>

<head>

<title> </title>
<meta charset='utf-8'>
<style>
	html, body{
		height:100%;
		margin:0;
		padding:0;
	}
	#right_menu, li{
		margin:0;
		padding:0;
		display:block;
	}
	#right_menu{
        overflow: hidden;
		width:70px;
		height:125px;
		background-color:#cccccc;
		border:2px solid;
		border-color: #dddddd #bbbbbb #bbbbbb #dddddd;
		padding-left:50px;
	}
	li{
		width:65px;

		margin:5px;

		font-family:arial, sans-serif;
		font-size:10pt;
		text-indent:5px;
	}
	li:hover{
		background-color:navy;
		color:white;
	}
	#b{
	top:50px;
	left:10px;
	}

</style>
<script>
   function animate(opts) {
  clearInterval(opts.el.timer);
  var start = new Date;
  var delta = opts.delta || linear;
  var height = parseFloat(opts.el.style.height);
  opts.el.timer = setInterval(function() {
    var progress = (new Date - start) / opts.duration;

    if (progress > 1) progress = 1;

    opts.step( delta(progress),height );

    if (progress == 1) {
      clearInterval(opts.el.timer);
      opts.complete && opts.complete();
    }
  }, opts.delay || 20);


}
function elastic(progress) {
  return Math.pow(2, 10 * (progress-1)) * Math.cos(20*Math.PI*1.5/3*progress)
}
function linear(progress) {
  return progress
}
function quad(progress) {
  return Math.pow(progress, 2)
}

function quint(progress) {
  return Math.pow(progress, 5)
}
function makeEaseInOut(delta) {
  return function(progress) {
    if (progress < .5)
      return delta(2*progress) / 2
    else
      return (2 - delta(2*(1-progress))) / 2
  }
}
function makeEaseOut(delta) {
  return function(progress) {
    return 1 - delta(1 - progress)
  }
}

window.onload = function() {
var input = document.getElementById("b");
var menu = document.getElementById("right_menu");
var body =  document.body;
var n = 0;
				input.onclick = function(){
				    n ^= 1;
                    var to = n ? 0 : 125,
                        display = n ? "none" : "block";
                     !n &&   (menu.style.display = display)
					animate({
					    el : menu,
						duration: 1000,
						delta: makeEaseInOut(linear),
						step: function(delta,height) {
							menu.style.height = delta*(to-height)+height+"px";
						},
                        complete :  function() {menu.style.display = display}
					})

				};

               body.onclick = function(event){
                 var event = event || window.event;
                 var target = event.target || event.srcElement;
                 if(target!=input && target!=menu &&!n && target.tagName != 'LI') input.onclick()

               }
}

</script>
</head>

<body>
<input type='button' id='b' value = 'Click'>
<ul id='right_menu' style="height: 125px">
	<li>Effect 1</li>
	<li>Effect 2</li>
	<li>Effect 3</li>
	<li>Effect 4</li>
</ul>

</body>

</html>

ksa 02.02.2014 20:39

Цитата:

Сообщение от Boolean_Type (Сообщение 295402)
это не от заказчика, а на курсах задали.

Какая разница чьи деньги? :)
Главное чтобы они кого-от заинтересовали... ;)

Boolean_Type 03.02.2014 15:51

Цитата:

Сообщение от рони
Вариант на основе темы

Рони, спасибо большое! В изучении пока не дошёл до анимации, поэтому пока не всё понятно в Вашем коде, но, как только дойду, обязательно подробно изучу каждую строку.
Кстати, пусть оффтоп, но: уже неоднократно на форуме сталкиваюсь в разл. темах с Вашими комментариями - и всегда с удовольствием их читаю. Честно, Вы круты!)
Насчёт задачи - кое-что таки наклепал сам:
<!DOCTYPE html>
<html>
<head>  
<meta charset=utf-8>
<title>JS Bin</title>
  <style>
 html, body{
		height:100%;
		margin:0;
		padding:0;
	}
	#right_menu, li{
		margin:0;
		padding:0;
		display:block;
	}
	#right_menu{
		position:absolute;
		width:65px;
		height:125px;
		background-color:#cccccc;
		border:2px solid;
		border-color: #dddddd #bbbbbb #bbbbbb #dddddd;
		padding-left:50px;
	}
	li{
		width:60px;
		height:25px;
		margin:5px;
		line-height:25px;
		font-family:arial, sans-serif;
		font-size:10pt;
		text-indent:5px;
	}
	li:hover{
		background-color:navy;
		color:white;
	}
	#b{
	position:absolute;
	left:10px;
	}
	  
  </style>
</head>
<body>
<ul id='right_menu'>
	<li></li>
	<li></li>
	<li></li>
	<li></li>
</ul>
<input type='button' id='b' value = 'Click'>
  
<script>
//запишем ссылку на объект-кнопку в перем-ую
var button = document.getElementById('b');

//получим контейнер UL в перем-ую
var menu=document.getElementById('right_menu');
//меню скрыто при загрузке стр-цы
menu.style.display='none';
//расположим кнопку справа-вверху от меню (позиционируем меню)
if(window.getComputedStyle){
	menu.style.left=parseInt(getComputedStyle(button).left)+'px';
	menu.style.top=parseInt(getComputedStyle(button).top)+'px';
}else{ //для IE8
	menu.style.left=parseInt(button.currentStyle.left)+'px';
	menu.style.top=parseInt(button.currentStyle.top)+'px';
}

var flag = false;

//ф-ция отображ-я меню
function show(){
    menu.style.display='block';
	
    //при выезжании меню текста нет
    var lis = document.querySelectorAll('li');
    for(var i=0; i<lis.length;i++){	
		lis[i].innerHTML = '';
	} 
	
	//ширина и высота меню
	var width = 0;
	var height = 0;
	
	return function frame_show() { // функция для отрисовки
		width++;
		height += 2; 
		menu.style.width = width + 'px';
		menu.style.height = height + 'px';
		
		if (width == 65) {
			clearInterval(timer_show); // завершить анимацию
			  
			//отразить текст в "гот." меню
			setTimeout(function(){
				var lis = document.querySelectorAll('li');    
				lis[0].innerHTML = 'Effect 1';
				lis[1].innerHTML = 'Effect 2';
				lis[2].innerHTML = 'Effect 3';
				lis[3].innerHTML = 'Effect 4';
			},50);
		}
	}
}

//ф-ция сокрытия меню 
function hide(){
	
    //при въезжании меню текста нет (чтоб не "маячил")
    var lis = document.querySelectorAll('li');
    for(var i=0; i<lis.length;i++){	
		lis[i].innerHTML = '';
	}
	
    if(window.getComputedStyle){
           var width = parseInt(getComputedStyle(menu).width);
           var height = parseInt(getComputedStyle(menu).height);
    }else{ //для IE8
	width = parseInt(menu.currentStyle.width);
           height = parseInt(menu.currentStyle.height);
    }

	return function frame_hide() { // функция для отрисовки 
		width--;
		height -= 2;
		menu.style.width = width + 'px';
		menu.style.height = height + 'px';
		
		if (height == 0) {
			clearInterval(timer_hide); // завершить анимацию
			
			//тут же скрыть меню полностью
			setTimeout(function(){
				menu.style.display='none';
			},60);
		}
	}
}

//переключать режим видимости контейнера (кликом по кнопке)
button.onclick=function(event){ 
	if(flag == false){
	timer_show = setInterval(show(),1);
	flag = true;
	}else{
	timer_hide=setInterval(hide(),1);
	flag=false; 
	}       
}

//скрыть контейнер при наж-ии вне кнопки     
button.onblur=function(event){
	timer_hide=setInterval(hide(),1);       
	flag=false;
}

</script>
</body>
</html>

рони 03.02.2014 16:21

Цитата:

Сообщение от Boolean_Type
При отладке выдаёт ошибку в строках 066,067

Цитата:

метод window.getComputedStyle ... Поддерживается всеми браузерами, кроме IE<9.
getComputedStyle и currentStyle

Boolean_Type 03.02.2014 16:47

Цитата:

Сообщение от рони (Сообщение 295591)

:yes: Да-да, уже исправил код в предыд. сообщении, думал, успею до того, как Вы увидите.)) Спасибо)

Я новичок, поэтому не знаю: как Вы сделали здесь код запускаемым?

рони 03.02.2014 16:55

Цитата:

Сообщение от Boolean_Type
как Вы сделали здесь код запускаемым?

О том, как вставить в сообщение исполняемый javascript и html-код, а также о дополнительных возможностях форматирования - читайте http://javascript.ru/formatting.

рони 03.02.2014 16:56

Boolean_Type, параметр run
[HTML run][/HTML]

Boolean_Type 03.02.2014 17:11

Цитата:

Сообщение от рони (Сообщение 295602)
О том, как вставить в сообщение исполняемый javascript и html-код, а также о дополнительных возможностях форматирования - читайте http://javascript.ru/formatting.

И снова спасибо!)

рони 03.02.2014 17:13

Boolean_Type,
:victory:

Boolean_Type 04.02.2014 20:37

Заметил ещё один негаразд кода :)
Если быстро жать на кнопку, размер меню в какой-то момент начинает бесконтрольно расти. В Хроме, например, достаточно клацнуть быстро 3 раза: на экране меню не будет, но в консоли можно увидеть, что ширина и высота контейнера быстро растут.
Я же чётко прописал:
if (width == 65) {
    clearInterval(timer_show);
 }

С чем связана эта странность и что можно с этим сделать?

рони 04.02.2014 20:58

Boolean_Type,
не делайте == используйте > или < посмотрите в консоли чему равна width и 3 клика возможно 3 таймера

Boolean_Type 05.02.2014 16:11

Цитата:

Сообщение от рони (Сообщение 295845)
Boolean_Type,
не делайте == используйте > или < посмотрите в консоли чему равна width и 3 клика возможно 3 таймера

Написал:
if (width >= 65 && height >= 130)
Всё равно проблема есть :(
Я тоже думаю, что дело здесь в конфликте одновременно запущенных таймеров, но всё равно не понимаю, как этот кон-т может провоцировать игнорирование условия в if... Числа в консоли мне ни о чём не говорят, просто после быстрого нажатия 3 и более раз высота и ширина растут без остановки... Чертовщина, короче :D

рони 05.02.2014 16:26

Boolean_Type,
а почему && ? а не ||

Boolean_Type 06.02.2014 00:32

Цитата:

Сообщение от рони (Сообщение 296045)
Boolean_Type,
а почему && ? а не ||

Потому что, когда ширина становится равной 65, высота становится равной 130. Я изначально написал width >= 65, без высоты, этого тоже вполне достаточно.
Можно и ||.
Тут в принципе неважно, как написать. Проблема в том, что при быстром клацанье все эти ограничители коту под хвост)))

рони 06.02.2014 00:40

Boolean_Type,
тут Основы программной анимации на JavaScript медитировать не пробовали?

Boolean_Type 06.02.2014 03:34

Цитата:

Сообщение от рони (Сообщение 296188)
Boolean_Type,
тут Основы программной анимации на JavaScript медитировать не пробовали?

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


Часовой пояс GMT +3, время: 16:01.