Html страница глазами разработчика приложений. Часть 2: «Реализация»

В Первой части мы подготовили нашу страницу.


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


Имитация базы, как мне уже писали в комментариях, это json файлы с содержанием нужного текста. Вопрос: «Зачем тут Vue? Если это можно написать и на скриптах?». Если честно — для красоты html верстки. Ну и изучения новых технологий.


Приступим!


На данной странице разделение вовсе не обязательно, ибо переменных тут не очень много, но я предпочитаю делить все на разные части. У нас будет компонент отвечающий за header, content & footer (позже появится).


Первое, это мы создаем json файлы, я создаю папку «data» и в ней создаю два файла «ru.json» и «en.json». В них соответственно названиям будет лежать наш текст. Далее открываем наш html и делаем подмены на будущее, стараясь назвать переменные так чтоб они полностью отображали смысл текста в них. В моем случае это было вот так:


 
                
                
                
//добален для компонента

{{aboutCompanyHeader}}

{{aboutCompanyText}}

{{ourMissionHeader}}

{{ourMissionText}}

//у вас может быть больше секций, у меня все секции собранны в данном div


Переходим к языковым файлам: (это можно добавить было все в один массив или один объект, но мне удобнее когда текст разбит подобным образом). «ru.json»


[
  { "main": "Главная" },
  { "aboutCompany": "О компании" },
  { "product": "Наша продукция" },
  { "equipment": "Наши технологии" },
  { "whereBuy": "Где купить" },
  { "service": "Поддержка" },
  { "partners": "Партнеры" },
  { "contacts": "Контакты" },
  {"aboutCompanyHeader": "О компании"},
  {
    "aboutCompanyText": [
      "«Хабрахабр» — крупнейший в Европе ресурс для IT-специалистов, издаваемый компанией «ТМ». ",
      "С момента появления в 2006-м году «Хабр» трансформировался из небольшого отраслевого сайта в глобальную ",
      "профессиональную площадку, которую ежемесячно посещают более 8 миллионов уникальных пользователей.",
      "«Хабрахабр» одинаково интересен программистам и разработчикам, администраторам и тестировщикам, дизайнерам ",
      "и верстальщикам, аналитикам и копирайтерам, а также всем тем, для кого IT — это не просто две буквы алфавита.",
      "Расширение тематики «Хабра» дало начало сайту-спутнику — Geektimes, на который переехали непрофильные хабы ",
      "и значительная часть контента, не имеющего непосредственного отношен разработке и программированию."
    ]
  },
  { "ourMissionHeader": "Наша миссия" },
  {
    "ourMissionText": [
      "Данный сайт представляет собой платформу для информационного обмена между участниками пользовательского ",
      "сообщества. Сообщество пользователей сайта является саморегулируемым, поэтому разобраться во всех нюансах ",
      "работы проекта с первого раза получается далеко не у всех. Чтобы объяснить, как всё устроено, мы подготовили ",
      "данный справочный раздел. Справа представлен рубрикатор справочного раздела. Для получения разъяснений выберите ",
      "соответствующий пункт рубрикатора и ознакомьтесь с предложенной информацией. Если вам не удалось найти ответ ",
      "на интересующий вопрос, пожалуйста, воспользуйтесь формой обратной связи."
    ]
  }
]


Ну и вы сами надеюсь справитесь с переводом данного текста на английский!


После проверки у меня перестало нормально работать меню с языками, поэтому если вы столкнулись с подобной проблемой, вот быстрое решение: «multilanguage.js»


  replaceElementAndSelect(userLanguage); 
//измененно
    $(document).on('click', '.flag ', function () {
        if (!isMenuClicked && !$(this).hasClass('select-flag')) {
            var newLang = $(this).attr('lang-value');
            language = newLang;
            setCookie("language", language);
            languageChange(newLang);
            hideMenu();
        }
        isMenuClicked = false;
    });

//измененно
    $(document).on('click', "#flag-menu", function () {
        isMenuClicked = true;
        showOrHideMenu();
    });

//замените все где используется menu на $('#lang-menu'). Например: menu.hasClass('lang-first-init') на $('#lang-menu').hasClass('lang-first-init'). В старом варианте у меня не работает. Если есть желание можете найти в чем проблема и ответить в комментариях


В папку «scripts» добавляем новый «main-function.js». И добавляем в него пару методов (т.к в моем случае они потом переиспользовались):


//Тут происходит сопоставление свойств компонента с объектами из json файла
function findInArray(langArray, component) {
    $.each(langArray,
        function (index, value) {
            Object.keys(value).forEach(function (key) {
                var val = value[key];
                if ($.isArray(val)) {
                    component[key] = val.join(", ");
                } else {
                    component[key] = value[key];
                }
            });
        });
}

//переиспользование для удобства написания кода
function getArrayFromJson(url) {
    return $.ajax({
        url: url,
        dataType: 'json'
    });
}


В папку «scripts» добавляем новый «index.js». И разбираем его


$(document).ready(function () {
    var language = getCookie("language") || navigator.language || navigator.browserLanguage; //ищем язык. Если нет в куках то берем браузерный

    //пути наших файлов с языковыми данными
    var ruUrl = location.origin + '/data/ru.json';
    var enUrl = location.origin + '/data/en.json';

    //массивы для данных, и Vue компоненты для обращения к ним
    var en = [], ru = [];
    var vm, vmHeader;

    initialize();

    //отлавливаем событие, если был поменян язык
    $(document).on('onLanguageChange',
        function (e, eventInfo) {
            setPageTemplateByLanguage(eventInfo);
        });

    function initialize() {
        //создаем Vue компоненты
        createMainComponent();

        //ждем пока придут данные с наших json файлов и отправляем их в массив
        $.when(getArrayFromJson(ruUrl), getArrayFromJson(enUrl))
            .done(function (a1, a2) {
                ru = a1[0];
                en = a2[0];
                setPageTemplateByLanguage(language); //для изменения языка
            });
    }

    function createMainComponent() {
        //записываем все наши переменные принадлежащие этому участку, их должно быть больше,но для примера сойдет
        vm = new Vue({
            el: '#contentPage',
            data: {
                siteHeader: "",
                siteSubHeader: "",
                aboutCompanyHeader: "",
                aboutCompanyText: "",
                ourMissionHeader: "",
                ourMissionText: ""
            },
            //у меня на странице была сторонняя библиотека которая создавала карусель из картинок, так вот после обновления компонента она "ломалась". Этот метод пересоздавал ее.
            updated: function () {
                this.$nextTick(function () {
                    // createCarusel();
                });
            }
        });

        vmHeader = new Vue({
            el: '#header',
            data: {
                aboutCompany: "",
                product: "",
                equipment: "",
                whereBuy: "",
                service: "",
                partners: "",
                contacts: ""
            }
        });
    }

    //в зависимости от языка перезаписываем данные в компонентах
    function setPageTemplateByLanguage(lang) {
        switch (lang) {
            case "en-US":
                findInArray(en, vmHeader);
                findInArray(en, vm);
                break;
            case "ru-RU":
                findInArray(ru, vmHeader);
                findInArray(ru, vm);
                break;
            default:
                findInArray(ru, vmHeader);
                findInArray(ru, vm);
                break;
        }
    }
});


Теперь осталось это добавить на нашу страницу, и не забыть скачать vue.min.js в папку «scripts»


    
    
    
    
    
    


В принципе вот и все, совсем немного кода для красивого решения!


Но я хочу пойти чуть дальше и добавлю пару Vue компонентов (для примера). Может будет кому-то от этого польза. Из новых компонентов это будет footer и заголовок сайта, а то у нас картинка выглядит пустой.


Создаем в папке «data» два файла: «footer_ru.json» и «footer_en.json»


[
  {"getInTouch": "Связаться"},
  {"region": "Россия, Санкт-Петербург"},
  {"street": "Невский проспект, дом 13 / 7" },
  {"phone": "8 (812) 666-66-66"},
  {"mobilePhone": "+7 (966) 666-66-66"},
  {"email": "ivanov@mail.ru"},
  {"secondEmail": "info@gmai.com"},
  {"findUs": "Ищите нас"},
  {"firstLine": "Инновация"},
  {"secondLine": "Мы помогаем"},
  {"firstPartLastLine": "2014 OOO "},
  {"colorPartLastLine": "Хабр "},
  {"thirdPartLastLine": "блог для разработчиков"}
]


Я это выношу в файл с общими функциями, т.к у себя я это переиспользую. Добавляем в «main-function.js»


// пути для данных 
var ruFooterUrl = location.origin + '/data/footer_ru.json';
var enFooterUrl = location.origin + '/data/footer_en.json';

var vueFooter;
var ruFooterInfo = [], enFooterInfo = [];

//следим за изменениями языка
$(document).on('onLanguageChange',
    function (e, eventInfo) {
        setPageTemplateByLanguageMain(eventInfo);
    });

//в общем сам футер
Vue.component('habr-footer',
    {
        props: ['get-in-touch', 'region', 'street', 'email', 'second-email', 'phone', 'mobile-phone', 'find-us',
            'first-line', 'second-line', 'first-part-last-line', 'color-part-last-line', 'third-part-last-line'],
        template:
            `
` }); //создание компонента и запись в него информации function createFooterComponent() { vueFooter = new Vue({ el: '#vueFooter', data: { footerInfo: { getInTouch: "", region: "", street: "", email: "", secondEmail: "", phone: "", mobilePhone: "", findUs: "", firstLine: "", secondLine: "", firstPartLastLine: "", colorPartLastLine: "", thirdPartLastLine: "" } }, created: function () { this.loadData(); }, methods: { loadData() { $.when(getArrayFromJson(ruFooterUrl), getArrayFromJson(enFooterUrl) ).done(function (a1, a2) { ruFooterInfo = a1[0]; enFooterInfo = a2[0]; setPageTemplateByLanguageMain(); }); } } }); } //в зависимости от языка перезаписываем данные в компонентах function setPageTemplateByLanguageMain(lang) { var userLanguage = lang || getCookie("language") || language; switch (userLanguage) { case "en-US": findInArray(enFooterInfo, vueFooter.footerInfo); break; case "ru-RU": findInArray(ruFooterInfo, vueFooter.footerInfo); break; default: findInArray(ruFooterInfo, vueFooter.footerInfo); break; } }


Чтобы это все было красиво, скачиваем Font Awesome и добавляем его в «css» папку.


В нашем «style.css» добавляем классы для красивого отображения:


.page-widgets-holder {
    border-top:1px solid #ccc;
}
.page-widgets-holder h3  {
    font-size:14px;
    text-align:center;
    color:#666;
    font-family: 'Montserrat', sans-serif;
    text-transform:uppercase;
    margin-bottom:40px;
    position:relative;
}
.page-widgets-holder h3:before {
    content:'';
    position:absolute;
    width:40px;
    height:2px;
    background:#ccc;
    bottom:-10px;
    left:50%;
    margin-left:-20px;
}

.contact-info li {
    float:left;
    width:100%;
    margin-bottom:12px;
}
.contact-info li a {
    font-family: 'Montserrat', sans-serif;
}
.ci-adress {
    text-transform:uppercase;
    font-size:14px;
    text-align:left;
    color:#000;
    line-height:20px;
}
.ci-mail {
    font-size:14px;
    text-align:left;
}
.ci-phone {
    color:#666;
    line-height:20px;
}
.social-links  {
    padding-bottom:58px;
}
.social-links li {
    display:inline-block;
    margin:0 1px;
    box-sizing:border-box;
}
.social-links li a {
    width:50px;
    height:50px;
    background:#eee;
    border-radius:100%;
    line-height:50px;
    float:left;
    color:#666;
    font-size:20px;
    box-shadow:0 0 0 20px transparent;
}
.social-links li a:hover {
    box-shadow:0 0 0 0 rgba(0,0,0,0.1);
}

.fa {
    margin-left: 0.75em;
    margin-top: 0.75em;
}


В «index.js» добавляем в метод «initialize ()»:


function initialize() {
        createFooterComponent(); //добавлено
        createMainComponent();

        $.when(getArrayFromJson(ruUrl), getArrayFromJson(enUrl))
            .done(function (a1, a2) {
              ........
            });
    }


И в «index.html» добавляем:


    

......


    
    
........
........


Ну и завершающий компонент, это заголовок сайта, я его добавляю в «main-function.js»:


var vmPageHeader, vueFooter;//добавлено 
var ruFooterInfo = [], enFooterInfo = [];
var ruHeaderInfo = [], enHeaderInfo = []; //добавлено 

Vue.component('habr-header',
    {
        props: ['site-header', 'site-sub-header'],
        template:
            `

{{ siteHeader }}

{{siteSubHeader}}

` }); //в данном случае создавать файл ради 2х строк невыгодно,поэтому мы добавляем данные в наши основные файлы и ссылки передаем сюда, где происходит поиск и сортировка нужной информации function createHeaderComponent(ruUrl, enUrl) { vmPageHeader = new Vue({ el: '#vueHeader', data: { siteSubHeader: "", siteHeader: "" }, created: function () { this.loadData(); }, methods: { loadData() { $.when( getArrayFromJson(ruUrl), getArrayFromJson(enUrl)) .done(function (a1, a2) { ruHeaderInfo = a1[0]; enHeaderInfo = a2[0]; setPageTemplateByLanguageMain(); }); } } }); } function setPageTemplateByLanguageMain(lang) { var userLanguage = lang || getCookie("language") || language; switch (userLanguage) { case "en-US": findInArray(enHeaderInfo, vmPageHeader);//добавлено findInArray(enFooterInfo, vueFooter.footerInfo); break; case "ru-RU": findInArray(ruHeaderInfo, vmPageHeader);//добавлено findInArray(ruFooterInfo, vueFooter.footerInfo); break; default: findInArray(ruHeaderInfo, vmPageHeader);//добавлено findInArray(ruFooterInfo, vueFooter.footerInfo); break; } }


В «en.json» и «ru.json» добавляем данные:


[
  { "siteHeader": "«Хабрахабр»" },
  { "siteSubHeader": "Данный сайт представляет собой платформу для информационного обмена между участниками пользовательского сообщества" },
..........
]


В «index.js» добавляем в метод «initialize ()»:


function initialize() {
        createFooterComponent(); 
        createMainComponent();
        createHeaderComponent(ruUrl, enUrl);//добавлено
        $.when(getArrayFromJson(ruUrl), getArrayFromJson(enUrl))
            .done(function (a1, a2) {
              ........
            });
    }


И в «index.html» добавляем:


    

......


    
    
........
........


Вот в принципе и все!


image


Исходный код можно найти ТУТ.


Только внимательно следите за путями к json-файлам, они у вас могут отличаться.

© Habrahabr.ru