Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Можно ли "повесить" внутренние функции на кнопки? (https://javascript.ru/forum/misc/60517-mozhno-li-povesit-vnutrennie-funkcii-na-knopki.html)

Keramet 04.01.2016 20:59

Можно ли "повесить" внутренние функции на кнопки?
 
Всем привет!
Вопрос такой: вот есть ДжС файл, который просто передвигает кнопку (типа анимация :write: ). Хочу нажать на кнопку, и она начинает двигаться. За начало "движения" отвечает функция start() Как задать её обработчику onclick на HTML странице?
Так не работает:
<input type='button' id="btn" onclick='startMove()'>

var main = function () {
	"use strict";
	var tmr;
	function stopMove ()    { clearInterval(tmr); }
	function startMove ()	{ tmr = setInterval(moveBtn, 24); }
	
	var moveBtn = function () {
		var btn = $("#btn");
		var left = parseInt( btn.css("margin-Left") ) + 1;
		btn.css("margin-Left", left + "px");
	};
	return startMove;
};
$(document).ready(main);

рони 04.01.2016 21:13

Keramet,
на всякий случай start плохое имя для функции.

Keramet 04.01.2016 21:17

startMove подойдёт? :agree: Исправил.

Keramet 04.01.2016 21:19

рони,
Исправление start() на startMove() не помогло :dance: шутка :)

рони 04.01.2016 21:25

Keramet,
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  </style>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script>
  var a;
     $(function(){
     var main = function () {
	"use strict";
	var tmr;
	function stop()	    { clearInterval(tmr); }
	function st()	{ tmr = setInterval(moveBtn, 24); }

	var moveBtn = function () {
		var btn = $("#btn");
		var left = parseInt( btn.css("margin-Left") ) + 1;
		btn.css("margin-Left", left + "px");
	};
	return st;
};
  // a = main()
   $("#btn").on({click : main()})
});


  </script>
</head>

<body>
<input type='button' id="btn"  value="click">
<!--<input type='button' id="btn" onclick='a()'>-->



</body>

</html>

Keramet 04.01.2016 21:30

рони,
У вас // a = main() вместо моего $(document).ready(main);?

Keramet 04.01.2016 21:32

или конструкция $(function(){.... то же, что и $(document).ready(main); ?

Keramet 04.01.2016 21:37

а где сам вызов st() из строки 18:
function st()   { tmr = setInterval(moveBtn, 24); }

и не совсем понял, зачем
$("#btn").on({click : main()})

мы ж на кнопку должны вроде повесить st() ?

рони 04.01.2016 21:42

Цитата:

Сообщение от Keramet
или конструкция $(function(){.... то же, что и $(document).ready(main); ?

да
Цитата:

Сообщение от Keramet
$("#btn").on({click : main()})

мы ж на кнопку должны вроде повесить st() ?

это и устанавливает обработчик или раскоментируйте строки а эту строку уберите.

рони 04.01.2016 21:44

Цитата:

Сообщение от Keramet
У вас // a = main() вместо моего $(document).ready(main);?

логику вашего варианта я не осилил, поэтому предложил два варианта на выбор.

Keramet 04.01.2016 21:50

по клину на кнопке Вы запускаете функцию main, это вроде понятно. Я просто не пойму, где происходит вызов st(). Ведь внутри main она не вызывается, только определяется.

Keramet 04.01.2016 21:53

моя логика была такая: вот эти строки
var tmr;
    function stopMove ()    { clearInterval(tmr); }
    function startMove ()   { tmr = setInterval(moveBtn, 24); }

не определять в глобальном контексте, а сделать это внутри функции (в данном случае main), которая запуститься как только броузер построит ДОМ ))

рони 04.01.2016 21:53

Цитата:

Сообщение от Keramet
по клину на кнопке Вы запускаете функцию main

нет - запускается не main а st -- в обоих вариантах

рони 04.01.2016 21:55

Цитата:

Сообщение от Keramet
которая запуститься как только броузер построит ДОМ

тогда main()() вместо $("#btn").on({click : main()})

Keramet 04.01.2016 21:56

Цитата:

Сообщение от рони (Сообщение 402567)
нет - запускается не main а st -- в обоих вариантах

Если Вам не сложно, можете указать, в какой строке Вашего кода происходит вызов st()?

рони 04.01.2016 22:00

Цитата:

Сообщение от Keramet
Если Вам не сложно, можете указать, в какой строке Вашего кода происходит вызов st()?

когда вы кликаите по кнопке $("#btn").on({click : main()}) -- main() в этой строке превратилось в st !!!
смотрите ранее что возвращает main => return st;

Keramet 04.01.2016 22:04

рони,
а, теперь вроде догоняю))

рони 04.01.2016 22:09

Keramet,
<!DOCTYPE HTML>

<html>

<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  </style>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script>
  var main = function () {

	var tmr;
	function stop()	    { clearInterval(tmr); }
	function st()	{ tmr = setInterval(moveBtn, 24); }

	var moveBtn = function () {
		var btn = $("#btn");
		var left = parseInt( btn.css("margin-Left") ) + 1;
		btn.css("margin-Left", left + "px");
	};
    st()
	return st;
};
$(main);


  </script>
</head>

<body>
<input type='button' id="btn"  value="click">




</body>

</html>

Erolast 04.01.2016 23:06

Цитата:

не определять в глобальном контексте, а сделать это внутри функции (в данном случае main), которая запуститься как только броузер построит ДОМ ))
Зачем?
Если определить функции внутри другой функции, то они только в ней видны и будут. Обработчики событий на элементах выполняются в глобальной контексте, и, соответственно, ни о каких stopMove и startMove они знать в принципе не могут.

Так что либо навешивай обработчик программно внутри функции main:
var main = function() {
    "use strict";
    var tmr;
    function stopMove ()    { clearInterval(tmr); }
    function startMove ()   { tmr = setInterval(moveBtn, 24); }
     
    function moveBtn() { //Объявляй уж в одном стиле
        var btn = $("#btn");
        var left = parseInt( btn.css("margin-Left") ) + 1;
        btn.css("margin-Left", left + "px");
    };
    
    $("#btn").on("click", startMove);
};
$(document).ready(main);


Либо объявляй функции глобально.

Keramet 04.01.2016 23:59

Цитата:

Сообщение от Erolast (Сообщение 402578)
Зачем?

в качестве эксперимента (идёт мой процесс обучения :help: )

Цитата:

Сообщение от Erolast (Сообщение 402578)
Зачем?
Если определить функции внутри другой функции, то они только в ней видны и будут.

я это понял. Хотел узнать, смогут ли в этом случае помочь замыкания

Цитата:

Сообщение от Erolast (Сообщение 402578)
Обработчики событий на элементах выполняются в глобальной контексте, и, соответственно, ни о каких stopMove и startMove они знать в принципе не могут.

я думал, что вызвав функцию main и вернув из неё обработчик, он (обработчик) будет доступен (благодаря замыканию).

Цитата:

Сообщение от Erolast (Сообщение 402578)
function moveBtn() { //Объявляй уж в одном стиле

а что не так я сделал?

Erolast 05.01.2016 09:09

Цитата:

я думал, что вызвав функцию main и вернув из неё обработчик, он (обработчик) будет доступен (благодаря замыканию).
Можно, Рони показал как: в обработчик надо ставить результат вызова функции main.

Можно еще то же самое, но не программно, а через аттрибут onclick кнопки:
<script>
function main() {
    "use strict";
    var tmr;
    function stopMove ()    { clearInterval(tmr); }
    function startMove ()   { tmr = setInterval(moveBtn, 24); }
      
    function moveBtn() { //Объявляй уж в одном стиле
        var btn = $("#btn");
        var left = parseInt( btn.css("margin-Left") ) + 1;
        btn.css("margin-Left", left + "px");
    };
     
    return startMove;
};
</script>
<button onclick="main()">Click me!</button>


Только не особо увлекайся с этими плясками. Если просто играешься - окей, но в продакшн старайся писать как можно проще.

Цитата:

а что не так я сделал?
Написал два фрагмента кода в разном стиле.
Да, тоже касательно этого отрывка, сразу не заметил: Function Declaration внутри блока - это уже ES6, так что в старых браузерах оно не заработает.

Keramet 05.01.2016 10:48

Erolast,
вот код страницы - не работает :(
<!doctype html>
<html>
	<head>
		<meta charset="utf8">
		<title>Макет!</title>
		<script src="js/jQuery.js"></script>
		<script>
			function main() {
				"use strict";
				var tmr;
				function stopMove ()    { clearInterval(tmr); }
				function startMove ()   { 
					tmr = setInterval(moveBtn, 24); 
					console.log("We START!!!");
				}
				
				function moveBtn() { //Объявляй уж в одном стиле
					var btn = $("#btn");
					var left = parseInt( btn.css("margin-Left") ) + 1;
					btn.css("margin-Left", left + "px");
				};
				
				return startMove;
			};
		</script>
	</head>
	
	<body>
		<header>
		</header>
		
		<main>
		       <img id="btn" src="img/button.gif">
		 </main>
		
		<footer>
			<input type='button' value='START' onclick='main()'> 
		</footer>
		
	</body>
</html>

рони 05.01.2016 11:08

Цитата:

Сообщение от Keramet
onclick='main()()'

:)

Keramet 05.01.2016 13:05

рони,
"Семён Сенёнович... А-а-а!" (с) :victory:
А как на другую кнопку повесить функцию stopMove() ? Как из main() вернуть 2 функции?

рони 05.01.2016 13:22

Keramet,
возвращайте обьект {stopMove :stopMove , startMove : startMove } тогда main().stopMove() и main().startMove()

а лучше main = main()

Keramet 05.01.2016 13:31

Цитата:

Сообщение от рони (Сообщение 402642)
а лучше main = main()

сорри - вот это не понял :(

рони 05.01.2016 13:37

Keramet,
<!doctype html>
<html>
	<head>
		<meta charset="utf8">
		<title>Макет!</title>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
		<script>
			function main() {
				var tmr;
				function stopMove ()    { clearInterval(tmr); }
				function startMove ()   {
				    stopMove ();
					tmr = setInterval(moveBtn, 24);
					console.log("We START!!!");
				}

				function moveBtn() {
					var btn = $("#btn");
					var left = parseInt( btn.css("margin-Left") ) + 1;
					btn.css("margin-Left", left + "px");
				};

				return  {stopMove :stopMove , startMove : startMove } ;
			};
           main = main()
		</script>
	</head>

	<body>
		<header>
		</header>

		<main>
		       <img id="btn" src="img/button.gif">
		 </main>

		<footer>
			<input type='button' value='START' onclick='main.startMove()'>
            <input type='button' value='STOP' onclick='main.stopMove()'>
		</footer>

	</body>
</html>

Keramet 05.01.2016 13:42

рони,
а со stopMove() не работает почему-то. я проверил таймер tmr, пишет undefined. Может его тоже в объекте возвращать из main() ? Или лучше его из startMove() возвращать?

Keramet 05.01.2016 13:46

Цитата:

Сообщение от рони (Сообщение 402645)
<script>
  function main() {
		....
  };
  main = main()
</script>

2 вопроса:
1) перед main = main() var нужен?
2) а может лучше заменить объявление функции на функциональное выражение? (var main = function () {...} )

рони 05.01.2016 14:25

Keramet,
1 нет
2 как хочешь, можно так
var main = (function () {...} )())

Erolast 05.01.2016 15:31

Цитата:

а может лучше заменить объявление функции на функциональное выражение? (var main = function () {...} )
Лучше. Переиспользовать переменную разными сущностями - это хрень какая-то. Не надо злоупотреблять динамической типизацией.

Цитата:

onclick='main()()'
Тьфу, да, точно.

Цитата:

А как на другую кнопку повесить функцию stopMove() ? Как из main() вернуть 2 функции?
Вот ты и начал натыкаться на грабли переусложнения.
Я бы лучше сделал как-то так:
<script>
	var startMoving;
	var stopMoving;

	(function() {
		"use strict";

		var timer; //Зачем здесь сокращение?
		
		startMoving = function() {
			timer = setInterval(function moveButton() {
				var target = $("#startMovingButton");
				var offset = parseInt(target.css("margin-left")) + 1;
				target.css("margin-left", offset + "px");
			});
		}

		stopMoving = function() {
			clearInterval(timer);
		}
	})();
</script>

<button id="startMovingButton" onclick="startMoving();">Start moving</button>
<button id="stopMovingButton" onclick="stopMoving();">Stop moving</button>


А вообще-то для подобного рода инкапсуляции в JS существует система модулей - https://learn.javascript.ru/modules.

Keramet 05.01.2016 18:24

Цитата:

Сообщение от рони
Цитата:

Сообщение от Keramet (Сообщение 402649)
1) перед main = main() var нужен?

Нет

Мы не ставим var, чтобы main была глобальной переменной? Или для чего? :) Насколько я разобрался - вся "магия" в этой строке

Erolast 05.01.2016 18:52

Нет, var не ставится потому, что переменная с названием main и так уже объявлена с помощью function main(){}. Функции в JS - сущности первого класса и тоже хранятся через помещение в переменную.
Собственно, любая функция - это объект-инстанс класса Function, наследника класса Object и имеет все признаки обычного объекта:
var func = function(){};
console.log(func.constructor == Function); // true
console.log(func instanceof Object); //true

func.property = 10;
func.property++;
console.log(func.property); //11;


Что насчет присвоения в глобал с помощью опущения var - да, такой трюк раньше действительно был возможен, но начиная с ES5 он запрещен. В строгом режиме попытка обращения к необъявленной переменной сгенерирует ошибку.

Keramet 05.01.2016 19:21

Erolast,
Это я понял. Объясните мне, зачем в коде рони main = main()?

Erolast 05.01.2016 19:56

main = main() - перезапись переменной main результатом вызова функции, находящейся (потом уже находившейся) в этой переменной.

Зачем? Нахрена-то)

Keramet 05.01.2016 19:59

Цитата:

Сообщение от Erolast (Сообщение 402701)
main = main() - перезапись переменной main результатом вызова функции, находящейся (потом уже находившейся) в этой переменной.

Зачем? Нахрена-то)

:haha:
Спасибо за вразумительное объяснение ))


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