<
  • Главная
Статьи

Я знаю jQuery. І що?

  1. 7 років тому…
  2. Раптово навігація по DOM стала простий
  3. розуміння Ajax
  4. Назад в майбутнє: сьогодні
  5. У яких випадках я завжди використовую jQuery
  6. 1. Коли проект повинен працювати в застарілих браузерах
  7. 2. Коли я роблю щось дешево і сердито
  8. Без jQuery!
  9. document.ready
  10. .attr ( 'value') і .attr ( 'href')
  11. classList - додаємо, видаляємо, перемикаємо
  12. Зберігання даних
  13. Ajax
  14. Нарешті форми!
  15. jQuery-анімації проти CSS-анімації і JavaScript-анімацій
  16. В сторону: jQuery-плагіни - просто так
  17. Висновок
  18. Матеріали до статті

На конференції jQuery UK 2013 я робив доповідь під назвою « Я знаю jQuery. І що? ». Зазвичай я готуюся, влаштовуючи вибух з стікерів на своєму столі, але в цей раз я спершу написав пост, а потім вже зробив слайди. Отже, ось мій практично не відредагований і трохи плутаний розповідь про те, як я працював з jQuery, і як я дивлюся на використання вбудованих браузерних технологій.

7 років тому…

17 червня 2006 року я опублікував мій найперший справжній пост в блозі : Я взяв звичайний JavaScript і спростив його за допомогою jQuery. В результаті 14 рядків JavaScript перетворилися в три рядки на jQuery (версії pre-1.0).

Найважливіший ефект від jQuery був в тому, що замість клопітно навігації по DOM ви писали простий CSS-селектор, після чого до потрібного елементу додавався клас. До того ж, вихідний JavaScript-код був досить нестабільним, а розмітка у вас виходила одна і та ж в обох випадках.

Я показав jQuery команді розробників, з якими я співпрацював в середині 2000-х, і навіть дизайнери побачили всі плюси цього підходу, оскільки CSS-селектори були їм уже знайомі (саме так і виникла ідея «jQuery для дизайнерів»).

Раптово навігація по DOM стала простий

В ті часи навігація по DOM була дуже складною. Можна було посперечатися - якщо у вас виходило щось зробити в Firefox 1.5, то в IE6 це не працювало.

Простота, з якою можна було вивчити jQuery, стала для мене плюсом. Вся навігація по DOM робилася за допомогою CSS-селекторів (реалізовано це було якийсь божевільної магією з «чорного ящика», яку придумав Джон Резіг) - головне, що це заощаджувало мої обмежені розумові ресурси, і, коли я отримував потрібні мені елементи DOM , я вже міг робити з ними все що завгодно (показувати, приховувати, анімувати і т.п.)

розуміння Ajax

jQuery також поставила на доступний мені рівень абстракцію Ajax. Цей термін був придуманий буквально тільки що, в 2005 році, і документації по технології було мало, зрозуміти її було непросто (не забувайте про обмежені обчислювальні можливості мого мозку).

Отже, мені потрібно було працювати з об'єктом XMLHttpRequest. Коли я побачив його вперше, мені коштувало зусиль зрозуміти, як працює подія onreadystatechange і пара this.status і this.readyState. jQuery, як і ряд інших бібліотек, розібралася з тим жахом, який представляли собою XHR-запити в IE через ActiveX ...

function getXmlHttpRequest () {var xhr; if (window.XMLHttpRequest) {xhr = new XMLHttpRequest (); } Else {try {xhr = new ActiveXObject ( "Msxml2.XMLHTTP"); } Catch (e) {try {xhr = new ActiveXObject ( "Microsoft.XMLHTTP"); } Catch (e) {xhr = false; }}} Return xhr; } // Код, який Джон написав в jQuery, // куди більш елегантний!

Коли я побачив, що в jQuery можна використовувати функцію ajax, для того щоб вицепіть HTML по якомусь адресою (саме це ми зазвичай і хотіли робити за допомогою Ajax), вся технологія раптово стала для мене зрозумілою.

jQuery відразу і надовго стала моїм звичайним інструментом. Це був мій «швейцарський ніж», якщо запозичити назва доповіді Адама !

Назад в майбутнє: сьогодні

Давайте промотали стрічку вперед і повернемося в сьогоднішній день. Що сталося за ці роки?

Для початку: моя позиція за замовчуванням - це не «завжди підключай jQuery». Я краще знаю JavaScript, і як в ньому все працює. У мене з'явилися власні критерії, коли потрібно підключати jQuery, а коли ні. Але якщо я не підключаю jQuery, що тоді?

За ці сім років відбулося досить багато. Ймовірно, одним з найважливіших кроків вперед стала поява в браузерах querySelectorAll.

Можливість передати вбудованої функції всередині браузера CSS-селектор, щоб сам браузер працював над навігацією по DOM - це величезна (правда!) Частина jQuery. Базова підтримка була в Chrome з самого початку, в IE8 і Firefox 3.5 з'явилася в середині 2009 року.

Ендрю Ланні (з PhoneGap і Adobe) написав неймовірно просту функцію:

var $ = document.querySelectorAll.bind (document); Element.prototype.on = Element.prototype.addEventListener; $ ( '# Somelink') [0] .on ( 'touchstart', handleTouch);

Це просто і прекрасно.

Я взяв його ідею, трохи розвинув її і використовував в ряді досить специфічних проектів, додавши підтримку для чейнінга, циклів і спростивши синтаксис. У стислому вигляді всі займає менше 200 байт. Сенс цього в тому, що зараз у нас є вбудована в браузери підтримка для ряду функцій, і я намагаюся брати до уваги аудиторію свого проекту, перед тим як за замовчуванням підключати jQuery.

У яких випадках я завжди використовую jQuery

Перш ніж я розповім про те, як я можу обходитися без jQuery, бути «голим» - давайте я розповім про випадки, коли я точно включаю jQuery в проект. Є кілька досить специфічних причин, які змушують мене або починати прямо з jQuery, або перемикатися на неї з якогось спеціально написаного рішення.

Перед цим я повинен зробити застереження щодо випадку, коли я абсолютно точно не використовую jQuery: якщо я намагаюся відтворити баг в браузері, я ніколи не використовую бібліотеку. Якщо ви намагаєтеся знайти баг, щоб можна було повідомити про проблему, необхідно, щоб в прикладі було якомога менше коду (звичайно, крім тих випадків, коли ви відправляєте повідомлення про помилку всередині jQuery!).

1. Коли проект повинен працювати в застарілих браузерах

BBC досить чітко озвучили, що саме вони називають сучасним браузером , І по деякому міркуванні це і є той ознака, по якому я вирішую, включати jQuery за замовчуванням чи ні.

Якщо я знаю, що я повинен працювати з несучасними браузерами, і вони складають частину ядра аудиторії, то я почну з jQuery всередині свого коду.

Що значить «сучасний»? За великим рахунком, відповідь проста: чи підтримує браузер querySelectorAll? BBC застосовує наступний тест на відповідність вимогу сучасності:

if (querySelector in document && localStorage in window && addEventListener in window) {// Завантажуємо JavaScript-додаток}

Я знаю напам'ять, що IE8 не підтримує addEventListener ( хоча і існує Поліфем ), Так що, якщо підтримка цього браузера важлива для проекту, я розумію, що не хочу починати проект з хаков для IE8.

Не те щоб я хочу сказати, що ті проекти, які я починаю без jQuery, не підтримуватимуть IE8. Швидше - що потрібно починати з малого і робити розробку простий з самого початку. Якщо я почну проект з оберемки хаков - проблем не оберешся.

І ще я вважаю це тим випадком, «коли складність переважує простоту».

2. Коли я роблю щось дешево і сердито

Якщо я створюю якийсь концепт, тестую ідею або просто щось накидаю і відправляю в JS Bin , Зазвичай я просто додаю jQuery за замовчуванням. Так мені не доводиться зайвий раз думати.

Без jQuery!

Напевно, ви думаєте: «Так, Ремі використовує jQuery, а якщо немає, то просто переписує всі фічі сам?»

Я абсолютно не хочу винаходити велосипед. Якщо я виявляю, що, розробляючи без jQuery, я в підсумку сам переписую з нуля її функціональність, тоді, ясна річ, я просто витрачаю свій час даремно.

Ні, все не так. Просто є досить багато сценаріїв, в яких я буду писати код свого застосування без бібліотеки, спираючись на вбудовані в браузер технології. Якщо якась частина цих технологій не підтримується в тому чи іншому браузері, я можу вдатися до поліфілії - але тільки після ретельного розгляду і розуміння, що це має сенс.

Отже, як я живу без jQuery, і наскільки повною можна вважати підтримку потрібних технологій в браузерах?

document.ready

Навіть коли я використовую jQuery, якщо у мене (або моєї компанії) є контроль над проектом, я дуже рідко використовую document.ready (або його коротку версію: $ (function)).

Справа в тому, що весь JavaScript я розміщую під всім DOM, перед тегом </ body>. Так я завжди впевнений, що в цей момент весь DOM вже буде оброблений браузером.

Сподіваюся, що ви це і так знаєте, але JavaScript блокує рендеринг сторінки. Якщо ви розмістите JavaScript над вмістом, і ваш сервер підвисне - ви отримаєте порожню сторінку. Я багато разів вже використав цей приклад, але повторюся, що раніше (досить давно) віджет Twitter просто вставлявся в HTML вашої сторінки. Їх сайт частенько падав, і мій блог (з цим віджетом) зависав на порожній сторінці - так що виглядало все так, ніби впав мій сайт.

.attr ( 'value') і .attr ( 'href')

Мені завжди стає сумно, коли я бачу, як jQuery використовується для того, щоб отримати значення елемента <input>:

$ ( 'Input'). On ( 'change', function () {var value = $ (this) .attr ( 'value'); alert ( 'The new value is' + value);});

Чому? Тому що завжди можна отримати значення елемента за допомогою this.value. Що важливіше - потрібно думати про те, як ви використовуєте JavaScript-бібліотеки. Чи не застосовуйте jQuery без необхідності.

Справа тут не в jQuery. Це просто нормальна практика. Потрібно, щоб в коді просто було написано:

$ ( 'Input'). On ( 'change', function () {alert ( 'The new value is' + this.value);});

Ще люди досить часто використовують jQuery для того, щоб отримати href посилання: $ (this) .attr ( 'href'), але можна цілком легко отримати шлях і з DOM: this.href. Зверніть, правда, увагу, що this.href дещо відрізняється: це абсолютний шлях, оскільки ми тут говоримо про DOM API, а не сам елемент. Якщо ви хочете отримати значення атрибута (як це працює в разі jQuery), ви можете використовувати this.getAttribute ( 'href').

Ще є сценарій, в якому ви встановлюєте клас для елемента, і тут вам теж не потрібна jQuery, якщо ви просто додасте клас. Скільки разів я бачив:

<Script src = "http://code.jquery.com/jquery.min.js"> </ script> </ head> <body> <script> $ ( 'body'). AddClass ( 'hasJS'); </ Script>

Але навіщо, коли можна так?

</ Head> <body> <script> document.body.className = 'hasJS'; </ Script>

Мабуть, найголовніша відмінність між цими двома прикладами полягає в тому, що ми не підключаємо jQuery тільки потім, щоб встановити клас для <body>, що визначає доступність JavaScript.

Якщо у <body> вже може бути який-небудь клас, то просто припишіть новий до рядка (jQuery теж потрібно звертатися до властивості className): document.body.className + = 'hasJS'.

Тут ми починаємо натикатися на проблеми з іменами класів і відстеженням того, у яких елементів якого класу є, а якого немає. Але в браузерах є і така функціональність.

classList - додаємо, видаляємо, перемикаємо

Властивість classList з специфікації HTML5 підтримується всіма останніми версіями браузерів (крім IE9 - але в цьому випадку я можу використовувати Поліфем).

замість:

$ ( 'Body'). AddClass ( 'hasJS'); // або document.body.className + = 'hasJS';

Можна написати:

document.body.classList.add ( 'hasJS');

Красиво, чи не так? А видаляти?

$ ( 'Body'). RemoveClass ( 'hasJS'); // або яке-небудь божевільне регулярний вираз

Або можна зробити так:

document.body.classList.remove ( 'hasJS');

Але більше вражає вбудована підтримка перемикання класів:

document.body.classList.toggle ( 'hasJS'); // і document.body.classList.contains ( 'hasJS');

Для додавання декількох класів потрібно додати їх як аргументи через кому:

document.body.classList.add ( 'hasJS', 'ready');

Є, звичайно, деякі проблеми, на кшталт цієї, з нового рядка:

document.body.classList.contains ( ''); // SyntaxError: DOM Exception 12

Жахливо! Але, з іншого боку, я знаю проблемні місця і обходжу їх стороною. В принципі, ми виросли, працюючи з браузерами саме за такими принципами.

Зберігання даних

Зберігання довільних даних в елементах з'явилося в jQuery в версії 1.2.3, а зберігання об'єктів - в 1.4, тобто вже досить давно.

У HTML5 є вбудоване зберігання даних усередині елементів, але між jQuery і вбудованою підтримкою є фундаментальна різниця: dataset в HTML5 не підтримує зберігання об'єктів.

Але якщо ви зберігаєте рядки або JSON, тоді вбудована підтримка працює ідеально:

element.dataset.user = JSON.stringify (user); element.dataset.score = score;

На жаль, вбудованої підтримки немає в IE10 (звичайно, можна додати Поліфему і все прекрасно запрацює - але це потрібно брати до уваги при використанні dataset).

Ajax

Як я вже говорив, jQuery допомогла мені зрозуміти Ajax в повній мірі. Зараз Ajax - це досить просто. Звичайно, у мене немає жодних додаткових опцій, але, здебільшого я просто виконую XHR GET або POST-запити з JSON.

function request (type, url, opts, callback) {var xhr = new XMLHttpRequest (), fd; if (typeof opts === 'function') {callback = opts; opts = null; } Xhr.open (type, url); if (type === 'POST' && opts) {fd = new FormData (); for (var key in opts) {fd.append (key, JSON.stringify (opts [key])); }} Xhr.onload = function () {callback (JSON.parse (xhr.response)); }; xhr.send (opts? fd: null); } Var get = request.bind (this, 'GET'); var post = request.bind (this, 'POST');

Коротко і просто. XHR - це зовсім не складно, а зараз є і хороша документація. Розуміння того, як XHR насправді працює і що з його допомогою можна зробити, дає нам більше можливостей.

Як щодо подій прогресу? Подій, прив'язаних до прогресу завантаження? Що щодо відправки ArrayBuffer? А якщо потрібно розбиратися з CORS і заголовком xml-requested-with?

Для цього вам знадобиться прямий доступ до об'єкта XHR (я знаю, що це можна отримати і з jQuery), і вам потрібно знати, як влаштований XHR і що з ним можна робити, тому що такі речі, як, наприклад, завантаження файлів через перетягування зараз шалено просто реалізувати за допомогою вбудованої функціональності.

Нарешті форми!

jQuery-плагін для валідації форм був стабільним плагіном з перших днів jQuery, і чесно зробив роботу з формами набагато простіше.

Але незалежно від валідації на стороні клієнта все одно потрібно проводити валідацію на стороні сервера - це необхідно в будь-якому випадку, яку б валідацію ви не робили.

Але що, якщо можна було б викинути купу рядків JavaScript і плагінів і затверджувати ел. адреса якось так:

<Input type = "email">

Хочете зробити його обов'язковим полем?

<Input type = "email" required>

Хочете вирішувати користувачу вводити тільки певні символи?

<Input pattern = "a-z0-9">

Не погано. Тут навіть є підтримка допоміжних технологій - наприклад, клавіатура на мобільних пристроях адаптується і буде виводити символи для ел. адреси.

Так як всі ці типи полів при відсутності в браузері підтримки просто стають текстовими полями, і якщо вже вам все одно потрібно робити валідацію на сервері, я б на вашому місці викинув всю JavaScript-валідацію і замінив її на вбудовану в браузери валідацію HTML5-форм.

jQuery-анімації проти CSS-анімації і JavaScript-анімацій

Насправді це ніякий не змагання. CSS виграє. Анімації, для яких використовується CSS, обчислюються на відеокарті. У анімаціях на JavaScript додається ще один рівень розрахунків - просто тому, що там є JavaScript.

Навіть в тому випадку, коли я пишу код сам, я виберу requestAnimationFrame замість використання анімацій, заснованих на setInterval.

Джейк Арчибальд підготував відмінні слайди, які показують проблему - setInterval зробить анімацію плавної, і досить скоро почне пропускати кадри:

Джейк Арчибальд підготував відмінні слайди, які показують проблему - setInterval зробить анімацію плавної, і досить скоро почне пропускати кадри:

Крім того, CSS-анімації проходять через той же таймер, що і requestAnimationFrame - його ми і хочемо використовувати.

Так що, якщо ваш браузер це дозволяє, використовуйте CSS-анімації. Звичайно, це складніше, ніж $ foo.animate ( 'slow', {x: '+ = 10px'}), але зате анімація буде чистіше і плавніше. Варто знати, що чіпати DOM - дорога операція. Якщо ви аніміруете положення елемента по осі абсцис, оновлюючи атрибут el.style.left, ви постійно читаєте і пишете в DOM.

А ось якщо ви просто зробите foo.classList.add ( 'animate'), анімація CSS-класу виконає плавний перехід положення лівої точки елемента. І якщо ви точно знаєте, що це тільки значення зліва, можна використовувати апаратне прискорення, виконавши translateX з translateZ (0).

Ну а як же, чую я ваш крик, як же виклик функції після закінчення анімації? Це теж можна. Хоча синтаксис трошки неприємний:

el.addEventListener ( "webkitTransitionEnd", transitionEnded); el.addEventListener ( "transitionend", transitionEnded);

Зверніть увагу, що e в end рядкова ...

Пара милих людей в Твіттері показали мені свого роду Поліфем для jQuery , Який доповнює функцію .animate в тому випадку, якщо в браузері доступні CSS-анімації.

Ще є окремий плагін Transit , Який дає вам можливість писати CSS-анімації на JavaScript. Приємний момент для мене - підтримка чейнінга. Але так він працює тільки з CSS-анімаціями, для цього потрібно IE10 або вище.

Звідси у мене виникає питання: чому цей плагін в обов'язковому порядку вимагає jQuery?

В сторону: jQuery-плагіни - просто так

Я:

Не знаю чому, але мені дуже хочеться боляче вдарити людей, які пишуть такі jQuery-плагіни, для яких насправді jQuery абсолютно не потрібна. / Требуется-контроль-емоцій

відповідь:

@rem У мене те ж саме. Я думаю, десь є група, в якій з цим допомагають, - і, гадаю, досить велика.

Я недавно працював над проектом і дізнався про fitText.js . Я вирішив включити його в свій код, але потім помітив, що для нього потрібно jQuery.

Хм-м. Навіщо?

Цей проект використовує такі методи jQuery:

  1. .extend
  2. .each
  3. .width
  4. .css
  5. .on (над продуктивністю ніхто особливо не замислювався)

Власне, ось код проекту:

$ .Fn.fitText = function (kompressor, options) {// Налаштовуємо var compressor = kompressor || 1, settings = $ .extend ({ 'minFontSize': Number.NEGATIVE_INFINITY, 'maxFontSize': Number.POSITIVE_INFINITY}, options); return this.each (function () {// Зберігаємо об'єкт var $ this = $ (this); // Функція Resizer () змінює розміри об'єкту // на основі його ширини, поділеної на compressor * 10 var resizer = function () { $ this.css ( 'font-size', Math.max (Math.min ($ this.width () / (compressor * 10), parseFloat (settings.maxFontSize)), parseFloat (settings.minFontSize)));} ; // Викликаємо для установки resizer (); // Викликаємо при ресайз. Opera кешує виклики за замовчуванням $ (window) .on ( 'resize orientationchange', resizer);}); };

.extend використовується на об'єкті, в якому всього дві опції, так що я б переписав його так:

if (options === undefined) options = {}; if (options.minFontSize === undefined) options.minFontSize = Number.NEGATIVE_INFINITY; if (options.maxFontSize === undefined) options.maxFontSize = Number.POSITIVE_INFINITY;

return this.each використовується для того, щоб ітерованих за елементами. Припустимо, що ми хочемо, щоб цей код працював без jQuery: тоді наша функція fitText отримає список елементів (так як чейнінга ми робити не будемо):

var length = nodes.length, i = 0; // Хотілося б використовувати [] .forEach.call, але немає підтримки в IE8 for (; i <length; i ++) {(function (node) {// там, де використовувався `this`, тепер` node` // ... }) (nodes [i]); }

$ This.width () отримує ширину контейнера, щоб змінювати розмір тексту. Для цього нам потрібно отримати розраховані стилі і взяти з них значення ширини:

// Функція Resizer () змінює розміри об'єкту // на основі його ширини, поділеної на compressor * 10 var resizer = function () {var width = node.clientWidth; // ...};

$ This.css використовується для установки значень, так що тут всього лише потрібно задати стилі:

node.style.fontSize = Math.max (...);

$ (Window) .on ( 'resize', resizer) прикріплює обробник події (якщо ви хочете підтримку в IE8, то потрібно ще включити addEvent):

window.addEventListener ( 'resize', resizer, false);

Насправді, я б пішов ще далі і зберігав би функції ресайз в масиві, і під час операції зміни розміру проходив би по масиву, виконуючи всі ці функції.

Звичайно, тут потрібно трошки більше роботи, але при цьому такі зміни досить легко провести так, щоб робота в якості jQuery-плагіна була б для цього проекту додатковою функціональністю, а не вимогою.

Моя тирада скоро закінчиться: ще мене вбиває, коли я бачу Поліфему якому потрібно jQuery - але я визнаю і контраргумент: надзвичайна поширеність jQuery, напевно, може виправдати те, що стільки проектів пишеться з залежністю від неї.

Висновок

Моєю метою було показати вам, що, хоча jQuery шалено допомагала мені всі ці роки (особливо роки погану сумісність між браузерами), і з вбудованою функціональністю браузерів можна піти досить далеко в плані звичайних сценаріїв, - коли я пишу JavaScript для того, щоб «зробити що-небудь »в DOM.

Перестаньте думати в парадигмі «функція X не працює в браузері Y». Підходьте під іншим кутом зору. Яке завдання я вирішую? Який інструмент найкраще підійде? Для кого це робиться? Я як і раніше вірю в методологію прогресивного поліпшення, але я не розумію задоволення лізти зі шкіри геть заради того, щоб підтримувати уявну аудиторію користувачів (з тієї причини, що у нас немає даних, які браузери у наших користувачів).

Google (за моїми останніми даними) підтримує останні і передостанні версії браузерів. Я теж намагаюся починати з підтримки цих версій.

Я буду продовжувати використовувати jQuery так, як мені зручно, і я продовжу переконувати своїх читачів і слухачів, що фронтенд-розробники повинні знати, що можуть браузери, з якими вони працюють.

Отже, на цьому я закінчую і сподіваюся, що цей текст був вам корисний.

Можливо, деякі з вас вже знали все це (правда, в такому випадку у мене виникає питання, навіщо ви це читаєте), однак я сподіваюся, що хоч комусь я показав, що за межами jQuery є ще цілий світ, і ви можете почати освоювати його прямо зараз в одному зі своїх проектів.

Може бути, деякі з вас тільки знайомляться з jQuery - я сподіваюся, що ви станете розбиратися і далі в тому, на що здатні JavaScript і DOM.

Однак більшості з вас я приніс сніг взимку. Ви вже згодні зі мною. Ви вже вірите в стандарти, робите все правильно, вчіться і утворювати. Але ви повинні допомогти людям, які не отримують цієї інформації.

Вам потрібно ділитися своїми відчуттями з іншими людьми. Тепер ви - експерти, і ви повинні допомогти оточуючим досягти вашого рівня і перевершити його.

На конференціях будуть потрібні нові доповідачі і нові експерти: це ви.

Матеріали до статті

Переклад оригінального запису « I know jQuery. Now what? »Ремі Шарпа (Remy Sharp), опублікованій на сайті remy sharp's b: log . Перекладено і опубліковано з дозволу автора.

переклад Влада Андерсена , редактура Вадима Макєєва и Ольги Алексашенко .

Теги: javascript , методика , думка

І що?
Що сталося за ці роки?
Але якщо я не підключаю jQuery, що тоді?
Що значить «сучасний»?
За великим рахунком, відповідь проста: чи підтримує браузер querySelectorAll?
Напевно, ви думаєте: «Так, Ремі використовує jQuery, а якщо немає, то просто переписує всі фічі сам?
Отже, як я живу без jQuery, і наскільки повною можна вважати підтримку потрібних технологій в браузерах?
А видаляти?
Opts?
Як щодо подій прогресу?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью