Jump to content

Great Rash

Expert
  • Posts

    7,974
  • Joined

  • Last visited

  • Days Won

    144

Everything posted by Great Rash

  1. Специально для тебя psywalker: onchange="this.parentNode.getElementsByTagName('input')[0].value = this.options[this.selectedIndex].text;" Это чтоб вопросов более не возникало
  2. Ладно признаю, что с innerHTML прокололся. Но дело совсем не в этом
  3. И снова здравствуйте, друзья и коллеги по несчастью! Вот выдалась свободная минутка и я спешу поделиться с вами совсем недавно (30 минут назад) найденным решением для стилизации селекта. Не секрет, что для многих это очень большая проблема, особенно когда попадается тупой заказчик и такой же дизайнер Итак без лишних слов качаем картинку select_bg.gif и разбираемся в коде: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>An XHTML 1.0 Strict standard template</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <style type="text/css"> .stylized_select { position: relative; overflow: hidden; width: 77px; height: 20px; background: url('select_bg.gif') 0 0 no-repeat; } .stylized_select select { position: relative; z-index: 2; width: 100%; -moz-opacity: 0; opacity: 0; filter: alpha(opacity=0); } .stylized_select .input_wrapper { position: absolute; z-index: 1; left: 0; top: 0; width: 53px; padding: 0 17px 0 7px; } .stylized_select .input_wrapper input { width: 100%; height: 20px; line-height: 20px; border: 0; background: none; } </style> </head> <body> <div class="stylized_select"> <select name="domen" onchange="this.parentNode.getElementsByTagName('input')[0].value = this.options[this.selectedIndex].innerHTML;"> <option value="1">opt 1</option> <option value="2">opt 2</option> <option value="3">opt 3</option> <option value="4">opt 4</option> </select> <div class="input_wrapper"> <input type="text" name="noname" value="opt 1" /> </div> </div> </body> </html> Проверял в: Mozilla Firefox 3.6 Apple Safari 5.0 Opera 10 Internet Explorer 7 InternetExplorer 8 В ИЕ 6 метод не работает, но пользователь в нем увидит совершенно обыкновенный селект без каких-либо изменений. Так что метод можно считать кроссбраузерным. Надеюсь, что с применением этого метода у вас станет одной головной болью меньше.
  4. В ИЕ при клике на ссылку блок едет справа налево, и никуда не сворачивается. Внутренность какого слоя? Скрипт работает только в ИЕ и Опере.
  5. Формула движения Так как мы будем делать движение не просто увеличивая координату, а движение с ускорением и замедлением, то нам понадобится некая формула движения. Я не математик, более того, с математикой я совсем не дружу, так что формулу расчета движения я искал очень долго и упорно гугля. И совершенно случайно наткнулся на один пост в форуме где эта формула приведена: x = начальная_координата + (конечная_координата - начальная_координата) * коэфицент; //где коэфицент = время_прошедшее_с_начала_анимации / время_за_которое_анимация_должна_закончиться; Время за которое анимация должна закончиться - это и есть наш параметр this.duration, который, как мы решили, по умолчанию равен 500 миллисекунд или 0,5 секунды. Единственное чего нет в нашем аниматоре, чтобы реализовать эту формулу движения - это свойства, в котором бы хранилось время, прошедшее с начала анимации. Чтобы узнать сколько времени прошло с начала анимации нам надо запомнить какое было время в момент клика по кнопке, для этого мы создадим новое свойство нашего объекта и назовем его, скажем startTime: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); // запоминаем время начала анимации, в миллисекундах this.move(); }, move: function() { if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { // производим расчет движения if (true) { window.clearInterval(self.obj.interval); } }, 10); } } Чтобы узнать сколько времени прошло с начала анимации нам надо внутри интервала вычитать из текущего времени время которое мы запомнили ранее: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); // запоминаем время начала анимации, в миллисекундах this.move(); }, move: function() { if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - this.startTime; // вычитаем из текущего времени время начала анимации if (true) { window.clearInterval(self.obj.interval); } }, 10); } } Тут мы сталкиваемся с одной проблемой. Дело в том что внутри нашей анонимной функции не будет переменной this.startTime, все это из-за того, что ключевое слово this в данном случае будет ссылаться не на наш объект Animate, а на объект window. Это прекрасно видно если запустить alert: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { alert(this); // проверяем куда ссылается this if (true) { window.clearInterval(self.obj.interval); } }, 10); } } Animate.init({obj: 'test', from: 0, to: 0}); // выдаст [object DOMWindow] или что-то вроде того Чтобы решить эту проблему нужно просто запомнить в переменной ссылку на наш объект, а потом обращаться к свойствам и методам нашего объекта через эту переменную: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; // запоминаем ссылку на наш объект (принято называть эту переменную self или parent) if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; // вот теперь все будет работать правильно if (true) { window.clearInterval(self.obj.interval); } }, 10); } } Теперь все готово для того чтобы реализовать движение нашего блока по формуле которую я привел выше: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; // запоминаем ссылку на наш объект if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; // высчитываем время, прошедшее с начала анимации var k = elapsedTime / self.duration; // высчитываем коэффициент, отношение прошедшего времени анимации ко времени анимации (изменяется от 0 до 1) var result = self.from + (self.to - self.from) * k; if (true) { window.clearInterval(self.obj.interval); } }, 10); } } Чтобы остановить анимацию в нужный момент (т.е. через 500 миллисекунд по умолчанию) нам надо проверить прошло ли уже пол секунды, т.е. равно ли отношение elapsedTime / self.duration единице (500 / 500 = 1), а для надежности лучше проверить не больше ли оно единицы: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; // запоминаем ссылку на наш объект if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; // высчитываем время, прошедшее с начала анимации var k = elapsedTime / self.duration; // высчитываем коэффициент, отношение прошедшего времени анимации ко времени анимации (изменяется от 0 до 1) var result = self.from + (self.to - self.from) * k; self.obj.style.cssText = self.attr + ': ' + result + self.units; // применяем полученный результат к анимируемому объекту if (k >= 1) { // если анимация дошла до конца, очищаем интервал, тем самым останавливая анимацию window.clearInterval(self.obj.interval); } }, 10); } } Как вы помните параметр this.attr у нас по умолчанию равен left, а параметр this.units - по умолчанию равен px, соответственно в результате у нас получится такая строка: self.obj.style.cssText = 'left: ' + result + 'px'; Теперь откройте html-файл с базовой версткой и на кнопки влево и вправо на событие onclick повесте вызов нашего аниматора: <div class="wrap"> <div class="left"> <!-- Двигаем справа налево --> <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test', from: 450, to: 0});" /> </div> <div class="right"> <!-- Двигаем слева направо --> <input class="button" type="button" value="→" onclick="Animate.init({obj: 'test', from: 0, to: 450});" /> </div> <div class="container"> <div id="test" class="item"></div> </div> </div> После этого откройте html-файл в вашем любимом браузере и понажимайте стрелки влево и вправо. Вы увидите, что красный блок будет ездить туда-сюда. Один проход блока будет занимать 0,5 секунды. Вы можете попробовать изменить скорость анимации, изменив параметр duration на необходимое значение: <!-- Двигаем медленнее --> <div class="wrap"> <div class="left"> <!-- Двигаем справа налево медленнее --> <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test', from: 450, to: 0, duration: 1000});" /> </div> <div class="right"> <!-- Двигаем слева направо медленнее --> <input class="button" type="button" value="→" onclick="Animate.init({obj: 'test', from: 0, to: 450, duration: 1000});" /> </div> <div class="container"> <div id="test" class="item"></div> </div> </div> <!-- Или двигаем быстрее --> <div class="wrap"> <div class="left"> <!-- Двигаем справа налево медленнее --> <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test2', from: 450, to: 0, duration: 250});" /> </div> <div class="right"> <!-- Двигаем слева направо медленнее --> <input class="button" type="button" value="→" onclick="Animate.init({obj: 'test2', from: 0, to: 450, duration: 250});" /> </div> <div class="container"> <div id="test2" class="item"></div> </div> </div> Отлично, все работает. Теперь осталось дело за малым - заставить наш блок двигаться с ускорением и замедлением. В нашей формуле var result = self.from + (self.to - self.from) * k; коэффициент - это как бы скорость красного блока в определенный момент времени. Чтобы получить движение с ускорением нам нужно чтобы с течением времени скорость становилась больше и больше, для этого будем возводить скорость (т.е. коэффициент k) в квадрат. Чтобы нам было удобней работать с изменениями коэффициента давайте создадим в нашем объекте еще один метод, который назовем например calculate, этот метод будет возвращать скорость возведенную в квадрат: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { // создаем новый метод return Math.pow(k, 2); // который возвращает коэффициент, возведенный в квадрат } } Давайте теперь снова запустим наш html-файл и посмотрим как ведет себя красный блок. Вы увидите что теперь он ездит туда-сюда с ускорением. Но теперь появилась еще одна небольшая проблема - дело в том, что наш коэффициент k изменяется от 0 до 1, а значит он является дробным числом, из-за этого (если несколько раз понажимать на стрелки) блок иногда немного переезжает за границу голубого блока или недоезжает до нее. Для того чтобы исправить это поведение давайте создадим еще один метод который будет исправлять неверные значения: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); result = self.fixResult(result); // исправляем неверное значение результата self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { return Math.pow(k, 2); }, fixResult: function(num) { // новый метод который будет исправлять результат num = Math.round(num); if (this.from < this.to) { // если блок едет слева направо if (num > this.to) { num = this.to; } if (num < this.from) { num = this.from; } } else { // если блок едет справа налево if (num < this.to) { num = this.to; } if (num > this.from) { num = this.from; } } return num; } } После всех дополнений, наш красный блок будет ездить как положено, а именно, строго в пределаз голубого блока. Давайте теперь реализуем движение с замедлением. Для начала давайте создадим еще один параметр у нашего аниматора. При помощи этого параметра мы будем переключать режим в котором будет ездить наш блок (с ускорением или с замедлением). Допустим параметр будет называться type и по умолчанию будет иметь значение accel (от английского acceleration): var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.type = params.type ? params.type : 'accel'; // новый параметр, по умолчанию равен ускорению - 'accel' this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); result = self.fixResult(result); self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { if (this.type == 'accel') { // если задано движение с ускорением return Math.pow(k, 2); // возвращаем коэффициент в квадрате } else { // если вдруг у нас задано иное невалидное значение this.type (например vasya_pupkin) return k; // тогда просто возвращаем коэффициент и блок поедет без ускорения } }, fixResult: function(num) { num = Math.round(num); if (this.from < this.to) { if (num > this.to) { num = this.to; } if (num < this.from) { num = this.from; } } else { if (num < this.to) { num = this.to; } if (num > this.from) { num = this.from; } } return num; } } Чтобы реализовать замедление, нам надо совершать действие обратное ускорению, т.е. действие обратное возведению в степень, а именно извлечение квадратного корня. Параметр, который будет отвечать за замедление давайте назовем decel (от английского deceleration): var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.type = params.type ? params.type : 'accel'; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); result = self.fixResult(result); self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { if (this.type == 'accel') { // если задано движение с ускорением return Math.pow(k, 2); // возвращаем коэффициент в квадрате } else if (this.type == 'decel') { // если задано движение с замедлением return Math.sqrt(k); // возвращаем квадратный корень из коэффициента } else { // если вдруг у нас задано невалидное значение this.type return k; // тогда просто возвращаем коэффициент } }, fixResult: function(num) { num = Math.round(num); if (this.from < this.to) { if (num > this.to) { num = this.to; } if (num < this.from) { num = this.from; } } else { if (num < this.to) { num = this.to; } if (num > this.from) { num = this.from; } } return num; } } Давайте попробуем все в действии: <!-- Двигаемся с ускорением --> <div class="wrap"> <div class="left"> <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test', from: 450, to: 0, type: 'accel'});" /> </div> <div class="right"> <input class="button" type="button" value="→" onclick="Animate.init({obj: 'test', from: 0, to: 450, type: 'accel'});" /> </div> <div class="container"> <div id="test" class="item"></div> </div> </div> <!-- Двигаемся с замедлением --> <div class="wrap"> <div class="left"> <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test2', from: 450, to: 0, type: 'decel'});" /> </div> <div class="right"> <input class="button" type="button" value="→" onclick="Animate.init({obj: 'test2', from: 0, to: 450, type: 'decel'});" /> </div> <div class="container"> <div id="test2" class="item"></div> </div> </div> Но самый интересный эффект - это движение сначала с ускорение, а потом с замедлением. Именно так движутся объекты в жизни, поэтому данный эффект выглядит наиболее естественно. Тут мои познания в математике заканчиваются и приходится обращаться к гуглю, вот какую формулу я нагуглил: Math.pow(k, 2) * (3 - 2 * k); Давайте применим ее. Параметр назовем both: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.type = params.type ? params.type : 'accel'; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); result = self.fixResult(result); self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { if (this.type == 'accel') { return Math.pow(k, 2); } else if (this.type == 'decel') { return Math.sqrt(k); } else if (this.type == 'both') { // если параметр равен both return Math.pow(k, 2) * (3 - 2 * k); // движемся сначала с ускорением, а потом с замедлением } else { return k; } }, fixResult: function(num) { num = Math.round(num); if (this.from < this.to) { if (num > this.to) { num = this.to; } if (num < this.from) { num = this.from; } } else { if (num < this.to) { num = this.to; } if (num > this.from) { num = this.from; } } return num; } } Ну вот мы и реализовали все базовые виды анимации объекта в нашем аниматоре. В принципе, для ускорения не обязательно возводить коэффициент в квадрат, если возводить его в куб (или в четверную степень и т.д.), то ускорение будет более резким. То же само е можно применить и к замедлению - для более выраженного эффекта надо извлекать кубический корень (или корень червертой степени), для этого нужно возводить коэффициент в степень 1/3. Я ввел еще один параметр в аниматор, чтобы иметь возможность изменять выраженность эффектов ускорения и замедления: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.power = params.power ? params.power : 2; this.type = params.type ? params.type : 'accel'; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.startTime = new Date().getTime(); this.move(); }, move: function() { var self = this; if (this.obj.interval) { window.clearInterval(self.obj.interval); } this.obj.interval = window.setInterval(function() { var elapsedTime = (new Date().getTime()) - self.startTime; var k = elapsedTime / self.duration; var result = self.from + (self.to - self.from) * self.calculate(k); result = self.fixResult(result); self.obj.style.cssText = self.attr + ': ' + result + self.units; if (k >= 1) { window.clearInterval(self.obj.interval); } }, 10); }, calculate: function(k) { if (this.type == 'accel') { return Math.pow(k, this.power); } else if (this.type == 'decel') { return Math.pow(k, 1 / this.power); } else if (this.type == 'both') { return Math.pow(k, this.power) * (3 - 2 * k); } else { return k; } }, fixResult: function(num) { num = Math.round(num); if (this.from < this.to) { if (num > this.to) { num = this.to; } if (num < this.from) { num = this.from; } } else { if (num < this.to) { num = this.to; } if (num > this.from) { num = this.from; } } return num; } } Ну вот мы и реализовали наш мини-фреймворк для анимации движения объектов. Что он умеет: 1) анимировать движение объекта по оси X или Y; 2) анимировать движение объекта с эффектами ускорения и замедления; 3) анимировать движения в пикселях или в процентах; 4) время анимации может изменяться по желанию пользователя; 5) аниматор имеет всего 3 обязательных параметра - id ноды или сама нода, начальная координата и конечная координата. Надеюсь что после прочтения этого урока вы научились создавать свои объекты, поняли принципы реализации больших фреймворков, поняли принципы анимации движения объектов в JavaScript и вообще почерпнули для себя много нового. Спасибо за внимание. Про вопросы, предложения, критику и лесть вы помните. P.S. Сайт, на котором я нашел основную формулу и формулу движения с ускорением и замедлением (easeInOut) - тут
  6. Объяснять задачу надо уметь. Вы такой вариант развития событий не допускали?
  7. Задачи которые решал я: Drag&drop Создание и удаление попапов (дивы, а не окна) Сортировка табличных данных Выпадающие меню, которые исчезают по таймауту Работа с формами, различные калькуляторы КАСКО, ОСАГО и т.п., появление/исчезновение определенных полей при определенном выборе и т.д. Нетривиальные задачи: Собственный контрол для формы - заменя стандартного селекта на свой с доп. функциолналом Свой скроллер Маски ввода в форме (например 1 123 432 567.12 для денег) Парсинг XML для создания дерева С аяксом жаль опыта почти нет...
  8. Great Rash

    HasLayout

    А если через JavaScript поставить object.hasLayout = 0;?
  9. ************************************************************************ Лирическое отступление номер два Вообще это не касается темы данного урока, но камрад s0rr0w верно подметил, что в этом выражении: this.x = params.x ? params.x : x; При значении x равном нулю параметр this.x примет дефолтное значение, т.к. 0 и false это одно и то же. Более того, так же интерпретируется и пустая строка. Чтобы убедиться в этом достаточно запустить вот такой код: alert(0 == false); // выдаст true alert('' == false); // выдаст true alert('' == 0); // выдаст true Я использую вот такой вариант проверки в подобной ситуации: // скобки в условии для наглядности this.x = (params.x || !isNaN(parseInt(params.x))) ? params.x : x; Возможно он немного корявый, но зато работает на все сто. ************************************************************************ Итак, продолжаем строить наш аниматор. Анимация в JavaScript Теперь нам необходимо приступать непосредственно к анимации блока. Как же реализовать анимацию на JavaScript, для этого мы можем использовать либо метод объекта window - setTimeout(code, timeout[,lang]), либо метод того же объекта - setInterval(code, timeout[,lang]). Оба эти метода могут принимать 3 параметра: code - код или функция, которая будет выполнена через определенный интервал времени; timeout - временной интервал в миллисекундах, через который будет выполнен код или функция; lang - необязательный параметр, язык на котором написана функция или код (JScript, VBScript или JavaScript). Различие между ними в следующем: setTimeout выполняется только один раз, а setInterval выполняется бесконечно, до тех пор пока не будет вызван метод clearInterval(interval_id), который очищает интервал, созданный методом setInterval. Аналогичный метод есть и для таймаута - clearTimeout(timeout_id). В нашем аниматоре мы будем использовать метод setInterval (мне он кажется более удобным). Итак, как мы и задумали, анимация движения будет происходить в методе move нашего объекта Animate: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.move(); }, move: function() { this.obj.interval = window.setInterval(someFunc, 10); // какая-то функция someFunc будет вызываться каждые 10 миллисекунд } } Здесь this.obj.interval - это индентификатор интервала, он нужен для того, чтобы по нему мы могли остановить анимацию вызвав метод clearInterval(this.obj.interval) у объекта window. Храним мы наш индентификатор как параметр ноды, которую двигаем, сделано это для того, чтобы мы в любой момент могли обратиться к нему. Так же вы можете установить иной временной интервал, но я методом тыка выяснил, что при таком значении анимация выглядит наиболее естественно. В принципе вы можете добавить дополнительный параметр к нашему объекту, который по дефолту будет равен 10 миллисекунд, но при желании можно будет задать иное значение. Теперь надо подумать как нам написать функцию someFunc. Можно конечно создать еще один метод в нашем аниматоре и потом вызывать его, но я предпочитаю создать в интервале анонимную функцию в которой и будут производиться все расчеты. Вот так примерно будет выглядеть скелет этой анонимной функции: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.move(); }, move: function() { this.obj.interval = window.setInterval(function() { // производим расчет движения if (true) { // при наступлении какого-либо условия очищаем интервал, тем самым останавливая анимацию window.clearInterval(self.obj.interval); } }, 10); } } Тут может возникнуть небольшая проблема: так как интервал относится не к нашему объекту, а к объекту window, может возникнуть два интервала (и более) если юзер кликнет на кнопку еще раз до того как анимация будет завершена. В этом случае будет создан еще один интервал, несмотря на то, что свойство interval у ноды this.obj будет перезаписано. Чтобы избежать этого, надо перед созданием нового интервала сначала очистить старый. Вот такой вид примет наш метод с дополнительной проверкой: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.move(); }, move: function() { if (this.obj.interval) { // если интервал уже существует window.clearInterval(self.obj.interval); // сначала очищаем его } this.obj.interval = window.setInterval(function() { // а потом создаем новый // производим расчет движения if (true) { // при наступлении какого-либо условия очищаем интервал, тем самым останавливая анимацию window.clearInterval(self.obj.interval); } }, 10); } } Ну вот и все пока. Продолжение следует. Про вопросы, предложения, критику и грубую лесть вы уже знаете
  10. Создаем базовый объект Итак нам надо продумать что должен уметь наш аниматор: во-первых, он должен уметь находить объект по id если ему передали id, так же было бы неплохо если бы ему можно было бы передать ноду вместо id (это иногда удобней); во-вторых, он должен уметь двигать объект по оси X или по оси Y, в зависимости от параметра который мы передадим ему; в-третьих, неплохо было бы передавать ему разные единицы измерения (пиксели, проценты); в-четвертых, анимация может длиться разное количество времени, значит мы будем передавать время (в миллисекундах) за которое должна будет проиграться анимация; в-пятых, объект должен знать откуда и куда должен будет ехать наш див; У нашего аниматора будет для начала 2 метода, первый - init (в нем мы будем получать входные параметры и запускать анимацию) и второй - move (в нем мы будем собственно двигать наш объект). Приступим к созданию объекта: var Animate = { // создаем объект (название объекта принято писать с большой буквы) init: function(params) { // это наш первый метод, в него передается объект params /* * тут "парсим" объект params * присваиваем дефолтные значения и т.п. */ this.move(); // а потом начинаем движение }, move: function() { // это наш второй метод, тут будем колдовать над анимацией } } Ну вот так примерно будет выглядеть наш аниматор, вызывать который мы будем так: <input class="button" type="button" value="←" onclick="Animate.init({параметр: значение, параметр: значение, параметр: значение});" /> ************************************************************************ Лирическое отступление номер раз Кому-то может быть непонятна такая запись: this.x = params.x ? params.x : x; Так вот это всего-лишь короткий эквивалент вот такой записи: if (params.x) { this.x = params.x; } else { this.x = x; } Некоторые иногда в условии ставят скобки для наглядности: // скобки в условии для наглядности this.x = (params.x) ? params.x : x; ************************************************************************ Продолжим создавать наш аниматор. Теперь нам нужно передать аниматору объект который мы собственно собираемся анимировать. Как мы решили это будет или id или нода. Делать мы это будем так: // для наглядности поставим в условии скобки this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; Если тип параметра равен string, т.е. если это строка значит мы передали туда id и тогда находим элемент по getElementById(id), если же это не строка, значит мы передали туда объект т.е. ноду, тогда просто передаем ее в параметр. Далее (согласно нашему плану) нам нужно передать аниматору относительно какой оси у нас будет ездить красный блок. За перемещение по оси X отвечает CSS-атрибут left, а за перемещение по оси Y - атрибут top. По умолчанию будем ездить по X: this.attr = params.attr ? params.attr : 'left'; Если атрибут задан, то передаем его в объект, иначе передаем в объект значение по умолчанию, в данном случае left. Аналогично по нашему плану задаем остальные параметры: // единицы измерения, по умолчанию пиксели this.units = params.units ? params.units : 'px'; // время анимации, по умолчанию пол секунды this.duration = params.duration ? params.duration : 500; // откуда будем ехать, по умолчанию значения не будет this.from = params.from; // куда будем ехать, по умолчанию значения не будет this.to = params.to; После всех манипуляций наш аниматор должен выглядеть примерно так: var Animate = { init: function(params) { this.obj = (typeof params.obj == 'string') ? document.getElementById(params.obj) : params.obj; this.attr = params.attr ? params.attr : 'left'; this.units = params.units ? params.units : 'px'; this.duration = params.duration ? params.duration : 500; this.from = params.from; this.to = params.to; this.move(); }, move: function() { } } А вот так мы его будем вызывать: <input class="button" type="button" value="←" onclick="Animate.init({obj: 'test', from: 450, to: 0});" /> Т.е. при клике на кнопку влево, наш блок поедет справа (с 450 пикселей - 500 минус 50 (ширина синего контейнера минус ширина красного блока)) налево (до 0 пикселей). Остальные параметры можно не задавать т.к. они не являются обязательными и примут дефолтные значения. Ну вот и все пока. Ждите продолжения, оно обязательно будет. Вопросы, предложения, критика и грубая лесть, как всегда, приветствуются.
  11. Базовая верстка Итак пришло время создать тестовую страничку, над которой мы будем экспериментировать: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Test</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <script type="text/javascript" src="animate.js"></script> <style type="text/css"> * { margin: 0; padding: 0; font: 12px Arial, sans-serif; } .wrap { overflow: hidden; width: 607px; border: 1px solid; } .button { width: 50px; height: 50px; text-align: center; } .left { float: left; } .right { float: right; } .container { position: relative; width: 500px; height: 50px; margin: 0 auto; background: #effeff; } .item { position: absolute; width: 50px; height: 50px; background: red; } </style> </head> <body> <div class="wrap"> <div class="left"> <input class="button" type="button" value="←" /> </div> <div class="right"> <input class="button" type="button" value="→" /> </div> <div class="container"> <div id="test" class="item"></div> </div> </div> </body> </html> Тут все очень просто. На стрелки мы будем тыкать, а красный квадрат будет туда-сюда ездить. Стили я выносить в отдельный файл не стал, а скрипт будет лежать в файле animate.js.
  12. Это опупенный инструмент. Вы читали статью «Grids are Good» в Google.? Если нет то прочтите (первая ссылка на пдф).
  13. Вступление Что мы будем делать: мини-фреймворк для анимации перемещения абсолютно или относительно позиционированных на странице объектов по оси X или Y. Сначала о главном: это мой первый опыт написания уроков, да и вообще статей, так что сильно не пинайте. У многих возникнет вопрос, зачем все это надо, если есть уже готовые фреймворки (jQuery, Prototype и т.п.)? Многие скажут излюбленную фразу про велосипед. Но вы их не слушайте, они просто буржуи – любят жить на всем готовеньком. А вот мы с вами – рабочий класс! А если серьезно, то иногда нет смысла подключать большой фреймворк ради одной единственной функции, в нашем случае анимации перемещения объекта. Ну и, опять же, опыт. Для начала немного про ООП В JavaScript’е объект можно создать двумя способами. Первый способ создание функции. В JavaScript объектом является любая функция: function Obj() { // объекты принято называть с большой буквы this.x = 1; this.y = 2; } Ключевое слово this является ссылкой на объект Obj. This.x и this.y – это его свойства Obj, т.е., говоря просто, это локальные переменные которые действуют только внутри объекта Obj. Так же у объекта есть методы. Метод – это функция внутри объекта. Работает она тоже только внутри него. У каждого объекта в JavaScript есть свойство prototype, при помощи которого можно добавлять новые методы объекту: function Obj(x, y) { // объявляем объект this.x = x; // добавляем свойство X равное параметру x, переданному в функцию this.y = y; // добавляем свойство Y равное параметру y, переданному в функцию } Obj.prototype.method = function() { // добавляем метод return this.x + this.y; // который будет возвращать сумму двух свойств } Мы создали наш объект и добавили ему свойства и метод, теперь осталось только создать его и начать использовать. Объект создается при помощи ключевого слова new, и может быть присвоен переменной или использоваться сразу: // можно так var o = new Obj(4, 5); alert(o.method()); // доступ к свойствам и методам происходит через точку // а можно так alert(new Obj(7, 8).method()); Неудобство такого подхода в создании объектов заключается в том, что в данном случае объект надо обязательно инициализировать при помощи ключевого слова new. Тут на помощь приходит второй способ создания объекта, а именно объектный литерал: var Obj = {} // а вот, собственно, и он Внутри объектного литерала свойства и методы записываются парами свойство: значение (имя_метода: функция) и отделяются запятыми. Похоже на ассоциативный массив ключ=>значение. var Obj = { // создаем объект x: 1, // добавляем свойство y: 2, // добавляем свойство method: function() { // добавляем метод return this.x + this.y; } } При таком стиле создания объекта нет необходимости в ключевом слове new и объект можно использовать сразу: alert(Obj.method()); Но тогда остается вопрос, как передать объекту параметры? Для этого можно создать отдельный метод, скажем init (я так и делаю), где параметры будут присвоены соответствующим свойствам объекта. Там же можно вызывать какой-либо метод: var Obj = { // создаем объект с методом init init: function(x, y) { this.x = x; this.y = y; this.method(); }, method: function() { return this.x + this. y; } } // и используем его Obj.init(2, 3); alert(Obj.method()); Так же в качестве параметра функции можно передать объект, для этого нужно записать в параметр объектный литерал, который потом можно использовать внутри нашего объекта. Для этого надо немного изменить метод init: var Obj = { // создаем объект с новым методом init init: function(params) { this.x = params.x; this.y = params.y; this.method(); }, method: function() { return this.x + this. y; } } // и используем его Obj.init({x: 5, y: 6}); alert(Obj.method()); Преимущества такого подхода заключаются в том, что нам становится совершенно неважно в каком порядке стоят передаваемые параметры: // не важно в каком порядке стоят параметры Obj.init({y: 6, x: 5}); alert(Obj.method()); А еще, при таком подходе мы можем добавлять дефолтные значения для некоторых параметров: var Obj = { // создаем объект с новым методом init init: function(params) { this.x = params.x ? params.x : 2; // если параметра X нет, то присваиваем дефолтное значение 2 this.y = params.y ? params.y : 2; // если параметра Y нет, то присваиваем дефолтное значение 2 this.method(); }, method: function() { return this.x + this. y; } } // вызываем метод с двумя параметрами Obj.init({x: 23, y: 32}); alert(Obj.method()); // а можно без одного из параметров Obj.init({x: 23}); alert(Obj.method()); // а можно и без другого Obj.init({y: 17}); alert(Obj.method()); Ну вот теперь вы должны немного представлять себе как устроены объекты в JavaScript'е и мы можем приступать собственно к построению самого фреймворка. Следите за темой, продолжение в следующем посте. Что почитать на тему: http://javascript.ru/tutorial/object http://designformasters.info/posts/objectifying-javascript/ «javascript ООП» в Google. Вопросы, предложения, критика и грубая лесть приветствуется. Прошу все писать в личку. Тему закрою во избежание флуда.
  14. margin: 0 auto; родительскому контейнеру футер прибит к низу
  15. Ну раз нечего критиковать тогда где грубая лесть?
  16. Копался в файликах с полезными решениями, которые я для себя сохраняю и наткнулся на интересную разработку (почти что собственного приготовления) Довольно часто, при верстке "резиновой" странички, возникает необходимость выровнять список со ссылками (допустим меню) по ширине. Казалось бы без таблиц тут никак не обойтись... Однако, около месяца назад (когда кто-то на форуме озадачился этой проблемой) я придумал довольно простое кроссбраузерное решение без использования таблиц. Без лишних слов привожу код: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Test</title> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <style type="text/css"> * { margin: 0; padding: 0; font: 11px "Trebuchet MS", Verdana, Tahoma, sans-serif; } ul { list-style: none; text-align: justify; text-justify: newspaper; line-height: 0; } li { display: -moz-inline-box; display: inline-block; vertical-align:top; text-align: center; background: red; } li.helper { width: 100%; background: none; } </style> <!--[if lte IE 7]> <style type="text/css"> ul { width: 99.9%; text-align-last: justify; } li { display: inline; } li.helper { display: none; } </style> <![endif]--> </head> <body> <ul> <li>home</li> <li>about us</li> <li>contacts</li> <li>some other link</li> <li class="helper"></li> </ul> </body> </html> Проверял в браузерах: Internet Explorer 6 Internet Explorer 7 Internet Explorer 8 Opera 10.10 Mozilla Firefox 3.6.3 Google Chrome 4.1.249 Apple Safari 4.0.5 Предложения, замечания, критика и грубая лесть приветствуются
  17. Ну и? <div id="block-menu-menu-kategorii" class="block block-menu block-odd region-odd clearfix style-menu "> Эту запись читаем так: блоку с id раному block-menu-menu-kategorii, присвоены классы: block, block-menu, block-odd, region-odd, clearfix и style-menu Что не понятно? Если вы не нашли в стилях какого-то класса, значит он просто не используется.
  18. Есть очень много вещей которые не получится сделать в ИЕ6, чтоб они выглядели как в современных браузерах. Это и понятно, уж сколько лет этому динозавру.
  19. psywalker, ну открой же виндовый калькулятор да посмотри как кнопки жать
  20. Math.log(x); - Returns the natural logarithm (base E) of x Описание отсюда
  21. Ну какбэ объект Math все умеет... 1) Math.sqrt(x); 2) Math.pow(x, y); - (x в степени y) 3) Math.sin(x); Сам недавно формулу извлечения корня n-ной степени искал через натуральный логарифм, ибо не был уверен (хотя вроде в школе давали), что 2 в степени 1/3 - то же самое что и корень 3 степени из 2. вот она (javascript): Math.exp(Math.log(x) / y); - (корень степени y из x)
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy