Translate

Поиск по этому блогу

Показаны сообщения с ярлыком блог. Показать все сообщения
Показаны сообщения с ярлыком блог. Показать все сообщения

суббота, 6 октября 2018 г.

Блог на NodeJS Express MongoDB ( III ).

Добавление постов - админ панель

Начать следует с добавления постов в блог. Для этого нам потребуется некая форма, которая будет принимать информацию от пользователя, обрабатывать ее и передавать на хранение в БД.



Все материалы по ES6


Добавление формы поста

Кнопка

На сайте Materialize возьмем кнопку.

Копируем код кнопки и добавляем в самый конец файла index.html.

Все что внутри тега ul удалим вместе с тегом. Это нам не нужно. Нам достаточно одной кнопки.



По ней сложно кликнуть, ничего не происходит. Поэтому надо поставит модальное окно.

Идем на сайт Materialize и там нам нужно посмотреть как работают модальные окна.

Берем modal-trigger и добавляем к ссылке нашей кнопки и далее нам нужно указать название модального окна, которое нам нужно открыть. Мы это будем делать через data-target="название"

Модальное окно

Так же берем с сайта Materialize готовый код окна и вставляем после кнопки.

Исправляем id - оно должно совпадать с значением data-target="createForm". Название поставим - "Создать новый пост", а вместо контента поставим поля ввода.

Файл index.html полностью


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <!-- Compiled and minified CSS -->
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"> 
 <!--Import Google Icon Font-->
 <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
 <title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
 <div class="container center" style="padding-top: 50px;">
  <div class="row">
   <div class="col s12 m8 offset-m2 lg6 offset-3" id="posts">
    <div class="preloader-wrapper small active">
     <div class="spinner-layer spinner-green-only">
      <div class="circle-clipper left">
       <div class="circle"></div>
      </div><div class="gap-patch">
       <div class="circle"></div>
      </div><div class="circle-clipper right">
       <div class="circle"></div>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
 <!-- button -->
 <div class="fixed-action-btn">
  <a class="btn-floating btn-large red modal-trigger" data-target="createForm">
   <i class="large material-icons">add</i>
  </a>
 </div>
   <!-- Modal Structure -->
  <div id="createForm" class="modal">
   <div class="modal-content">
    <h4>Создать новый пост</h4>
    <div class="input-field">
     <input id="title" type="text" class="validate" required>
     <label for="title">Название.</label>
    </div>

    <div class="input-field">
     <textarea id="text" class="materialize-textarea"></textarea>
     <label for="text">Название.</label>
    </div>
   </div>
    <div class="modal-footer">
      <a class="waves-effect waves-light btn" id="createPost">Создать пост.</a>
    </div>
  </div>

 <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
 <script src="index.js"></script>
</body>
</html>



Теперь нужно проинициализировать модальное окно

На нужно передать в глобальный объект Материалайза элемент, который нам нужно проинициализировать и после этого все должно работать.

M.Modal.init(elems, options);

Поэтому идем в скрипт - index.js

Уберем за одно и таймаут. Он нам уже не нужен.

Инициализируем модальное окно.

M.Modal.init(document.querySelector('.modal'))

внутри события загрузки всего документа.

Создаем глобальную переменную modal вверху файла и занесем в нее инстанс модального окна внизу, чтобы в последствии им можно было управлять.

Файл index.js


const card = post => {
 return `
    <div class="card z-depth-4">
         <div class="card-content">
           <span class="card-title">${post.title}</span>
           <p>${post.text}</p>
           <small>${post.date}</small>
         </div>
         <div class="card-action">
      <button class="btn btn-small red">
       <i class="material-icons">Delete</i>
      </button> 
         </div>
       </div>
 `
}

const BASE_URL = '/api/post'
let posts =[]
let modal;
class PostApi {
 static fetch(){
  return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
 }
}

document.addEventListener('DOMContentLoaded', () => {
 PostApi.fetch().then(backendPosts => {
  posts = backendPosts.concat()
  renderPosts(posts)  
 })
 modal = M.Modal.init(document.querySelector('.modal'))
})

function renderPosts(_posts=[]) {
 const $posts = document.querySelector('#posts')
 if(_posts.length > 0) {
  $posts.innerHTML = _posts.map(post=> card(post)).join()  
 } else {
  $posts.innerHTML = `<div class="center">Постов пока нет.</div>`
 }
}



Проверяем.



Придаем функциональность

Первое, что нам нужно сделать, это поставить прослушку события на кнопку в модальном окне. Когда мы кликаем по кнопке "Создать пост" мы будем вызывать функцию.

Внутри основного события загрузки документа в файле index.js возьмем кнопку -

document.querySelector('#createPost').addEventListener('click', onCreatePost)

Функцию мы вызываем без круглых скобок - просто передаем название.

Создаем функцию onCreatePost

В ней мы должны получит контент, который написан в инпутах. Посему, создадим переменные

$title = document.querySelector('#title')
$text = document.querySelector('#text')


Проверим, что эти поля не пустые:

if ($title.value && $text.value)

Если они не пустые, то нам нужно отправить POST-запрос, который мы реализовывали на сервере.

Для этого создадим date, которую мы хотим отправить на сервер. На сервере мы ожидаем увидеть два поля - title и text с запросом.

Поэтому мы здесь создадим новую переменную - newPost


  const newPost = {
   title: $title.value 
   text: $text.value
  }


И теперь когда у нас есть данные которые мы принимаем на сервере (объект) нам нужно отправить запрос.

Для этого у нас есть вспомогательный класс PostApi и давайте здесь же реализуем метод, который нам позволит создавать посты.

 static create(post) {

 }
Будет принимать объект поста.

Далее мы будем возвращать результат работы метода fetch(BASE_URL) по BASE_URL и далее нам необходимо передать объект конфигурации {}

Во первых мы ожидаем, что будем отправлять метод POST, поэтому


 static create(post) {
  return fetch(BASE_URL, {
   method: 'post',
  })
 }



Далее нам необходимо указать body (посмотрите на сервер - title: req.body.title, text: req.body.text, (14 и 15 строка файла routes/post.js)

Поэтому в методе fetch() мы так и пишем body и далее нам необходимо сделать строкой - сериализовать объект post

Сделаем так:

JSON.stringify(post)

Так же нам нужно здесь реализовать хедеры, чтобы сервер понимал, что работа идет с JSON-ом.


   hraders: {
    'Accept': 'application/json',
    'Content-Type':'application/json'
   }



Конфигурация запроса на этом закончена и после того, как пройдет метод fetch мф хотим получить некоторый body. Для этого в методу .then(res => res.json()) делаем то, что обычно с запросом. Отдаем некоторый json.

Метод create готов.


class PostApi {
 static fetch() {
  return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
 }
 static create(post) {
  return fetch(BASE_URL, {
   method: 'post',
   body: JSON.stringify(post),
   hraders: {
    'Accept': 'application/json',
    'Content-Type':'application/json'
   }
  }).then(res => res.json())
 }
}



Теперь у нас метод create готов и мы можем продолжить работу.

В функции onCreatePost мы сформировали новый пост и далее можем обратиться к классу PostAPI и с помощью метода create() передать ему данные - newPost и далее, когда обработается запрос и сервер нам ответит, в метод .then() мы получим новый объект post.

Нам нужно отобразить его в списке всех постов. Для этого у нас есть локальная переменная posts, гд хранятся все посты. Мы просто добавим его туда методом push()

И далее. чтобы отобразить новые посты, мы вызываем метод renderPosts(posts) c массивом posts.

Помимо того. что мы создали пост на сервере нам нужно сразу закрыть модальное окно -

modal.close()

И очистим значения инпутов -

$title.value = ''
$text.value = ''


И обновим текстовые инпуты - Обратиться к библиотеке материолайз и вызвать метод

M.updateTextFields() - по новому отобразит текстовые инпуты.

Сейчас при попытке создания посты мы получим следующее сообщение:



Для правильной работы нашего сервера нам нужно добавить плагин, который будет за нас парсить входящие данные. Мы с клиента их сериализовали - превратили в строку и теперь нужно сделать так, чтобы сервер их принимал как обычный JS-объект.

Для этого нам потребуется пакет body-parser

Остановим выполнение сервера.

Установим пакет, который автоматически будет парсить за нас входящие данные.

npm install body-parser


Подключаем его в папке app.js где-нибудь вверху.

const bodyParser = require('body-parser')

Теперь нужно применить пакет к нашему серверу.

Например. пред тем, как мы определяем роуты мы можем написать такую конструкцию:

app.use(bodyParser.json())

Будет преобразовывать входящие параметры в json-объект.

app.js


const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const path = require('path')
const postRouter = require('./routes/post')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
   .then(() => console.log('MongoDB connected'))
   .catch(err => console.error(err)) 
const app = express()
app.use(bodyParser.json())
app.use('/api/post', postRouter)
app.use(express.static(clientPath))
app.listen(port,()=>{
 console.log(`Server run on ${port} port`)
})



Запускаем сервер

Добавляем пост:



Если обновить страницу, то мы все равно увиим данный пост, потому что он берется уже из БД. В консоли можно посмотреть данные поста



Если посмотреть в mLab в коллекциях то мы увидим данные нашего поста.



Теперь можно добавлять посты на страницу.

Мы реализовали функционал по фетчингу и добавлению постов. осталось добавить удаление поста и правильный вывод даты, а так же сохранить форматирование строк поста.

Реализация удаления поста.

Нас интересует клиентский скрипт - index.js

Здесь есть функция, которая вызывается когда полностью загрузится контент DOM. В ней у нас уже есть прослушка событий на кнопке "Добавить пост". Создадим еще одну, которая позволит нам удалять определенные посты. В данном случае мы будем делегировать события и прослушку повесим на весь cписок постов (id="posts"), потому что на кнопку удаления повесить ее мы не можем, так как они все время меняются. Поэтому лучше делегировать события.

document.querySelector('#posts').addEventListener('click', onDeletePost)

и создаем данную функцию внизу файла.

В нее принимаем некоторый event

Теперь нам нужно определить, что нам нужно что-то удалить. Так как сейчас событие event будет срабатывать при клике по любому месту поста.

Нам нужно понять, что клик был именно по кнопке удаления поста.

Для этого мы можем в функции, которая генерирует нам html-карточки добавить на кнопку удаления поста специальный класс, напрмер .js-remove

Теперь нужно в функции определить, есть ли у элемента по которому мы кликнули этот класс.

В конструкцию if запишем: если у event.target в объекте classList есть класс .js-remove, то мы что-то делаем.

if (event.target.classList.contains('js-remove'))

далее спросим у пользователя через функцию confirm желает ли он удалить этот пост.

const decision = confirm('Вы уверены, что хотите удалить пост?')

А далее если пользователь нажал (согласился), то нужно понять какой именно пост нужно удалить.

Нам для этого нужно получить id поста. id хранится в объекте post._id. И зная что мы будем кликать именно по кнопке удаления, мы можем на кнопку добавить атрибут - data-id="${post._id}" и будем забирать именно этот атрибут.

const id = event.target.getAttribute('data-id')

Далее, зная нужный id мы можем отправить его на сервер.

Для этого нам нужно реализовать функцию удаления в классе PostApi.

Там мы создадим новую функцию static remove(id) в нее мы будем получать id и все что мы будем делать - возвращать функцию fetch() по BASE_URL но к нему надо еще добавить id, поэтому В параметрах метод delete, потому что мы будем слушать именно его. и после этого получим результат.


 static remove(id) {
   return fetch(`${BASE_URL}/${id}`, {
    method: 'delete'
   }).then(res => res.json())
 }



Теперь мы можем обратиться к классе PostApi взывать у него метод remove передать ему нужный id и как только сервер ответи успехом, мы в функции .then() удалим пост из списков (визуально)


function onDeletePost(event) {
 if (event.target.classList.contains('js-remove')) {
  const decision = confirm('Вы уверены, что хотите удалить пост?')

  if (decision) {
   const id = event.target.getAttribute('data-id')

   PostApi.remove(id).then(() => {
    const postIndex = post.findIndex(post => post._id === id)
    posts.splice(postIndex, 1)
    renderPosts(posts)
   })
  }
 }
}



Правильно указать дату поста и мультимтрочный текст

Текст.
Параграфу просто добавить инлайн стиль white-space:pre-line



Для нормального отображения даты нужно поле ${post.date} обернуть в конструктор ${new Date(post.date).toLocaleDateString()}

Метод приводит даты к локальному формату.

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





                                                                                                                                                             

среда, 3 октября 2018 г.

Блог на NodeJS Express MongoDB ( I ).

С этого поста начинаем разработку блога с использованием fullstack - технологий.



Все материалы по ES6




Самое простое объяснение, что такое fullstack - разработка клиентской и серверной частей. Разработка идет двух этих сущностей независимо друг от друга, а потом мы их связываем в единый блок.

В этих трех постах мы создадим блог, где мы сможем создавать посты, выводить их и удалять.

Сервер мы напишем на NodeJS с использованием фреймворка Express. Плюс, мы будем связываться с фронтэндом, который будет написан на нативном JavaScript через REST.API

  1. Создадим папку нашего проекта. Я создал папку - fs-blog.


  2. Нам потребуется установленная NodeJS.

    Проверить очень просто. В КС (здесь и далее - командная строка) нужно ввести:

    node -v


    Enter

    Если NodeJS установлена, то уведите ее версию, а если нет, то ее стоит установить с официального сайта. Это очень просто и я останавливаться на этом не буду.


  3. Инициализация проекта.

    Эту необходимо сделать для автоматической генерации файла package.json, где будут храниться все зависимости нашего проекта.

    Переходим в КС в папку проекта. Для этого можно использовать команду

    cd NameFolder


    Можно просто перетащить папку в КС и получить путь, можно начать вводить имя папки и нажать Tab.

    После того, как вы оказались в папке проекта, в КС вводите:

    npm init


    Здесь мы можем ввести необходимые данные в файл package.json - зависимости и настройки нашего проекта.

    Можно добавить описание - description: simple blog

    entry point - это основной файл (точка входа в проект). Я укажу app.js

    keywords: blog, node.js, fullstack

    Avtor: Your Name

    y

    Enter

    Теперь в корне проекта мы получим файл package.json где хранятся все данные, которые мы добавляли через КС.


  4. Создание точки входа app.js

    В этом файле мы будем вести разработку нашего сервера.


  5. Устанавливаем фреймворк Express.


npm install express


В современных npm версиях указывать флаг --save не нужно. Зависимости и так пропишутся автоматически в файле package.json.

Если посмотреть, то в файле package.json появится ваша версия "express" в разделе "dependencies"

В папке node_modules хранятся файлы библиотеки, и появится файл pachage-lock.json, который служит для разруливания различных зависимостей и версий пакетов. Его трогать не нужно. Он генерируется автоматически.

Создание и запуск сервера.

Давайте разберемся - с чего начинается разработка сервера на Express.

  1. - Нам нужно подключить сам Express к нашему проекту.

    const express = require('express')

    Создали одноименную фреймворку переменную, куда с помощью глобальной для Node.js функции require() положили фреймворк, а точнее содержимое папки express, которая находится в node_modules.Указываем не путь, а название пакета и NodeJSпонимает, что данный пакет нужно брать из папки node_modules.


  2. -создаем сервер в переменной, которая будет отвечать за наше приложение - app.

    const app = express()

    Таким образом мы получили объект app, который будет ключевым для нашего сервера.


  3. - для запуска сервера нужно указать Экспресу о том, что мы будем что-то слушать :-)


Создадим переменную const port = 5000

Для запуска сервера нам нужно обратиться к объекту app, его методу listen()-с помощью этого метода мы можем запускать прослушку всего сервера. Первым параметром в этот метод мы передадим номер порта где мы хотим все это слушать ( наша переменная port). Вторым параметром - callback-функцию, которая будет вызвана, когда сервер заработает.

Для порта допишем функциональность. Обычно, мы можем передавать различные переменные, информацию через консоль в NodeJS и обычно порт передается через консоль, например, если мы будем куда-то выкладывать наш проект. Поэтому нам нужно проверить - если у нас указана системная переменная, которая содержит номер порта, тогда мы будем использовать её, а если нет, то порт 5000. Для того, чтобы в NodeJS обратиться к каким-то системным переменным, мы обращаемся к глобальному объекту process. У него есть объект environment (окружение) и название параметра, если он существует. А если его нет, то порт 5000:

const port = process.env.PORT || 5000

Таким образом мы получили файл app.js


const express = require('express')

const port = process.env.PORT || 5000

const app = express()

app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Запустим сервер:

node app.js


В консоли мы увидим Server run on 5000 port



Перейдем по адресу localhost:5000

Если мы увидим вот такое сообщение - Cannot GET /, значит сервер запущен и все работает правильно.



Давайте еще подготовим наше окружение для работы.

Переходим в файл package.json и напишем два скрипта в поле "scripts". Сейчас здесь есть один тестовый скрипт. Он нам не нужен и мы его удалим. Вместо него запишем скрипт, который будет запускать весь наш сервер:


  "scripts": {
    "start": "node app.js"
  },



Теперь в консоли (КС) мы можем для запуска приложения (сервера) написать команду:

npm run start


И нажать Enter.



Отдаем html-страницу.

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

Внутри нее создадим файл - index.html.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<h1>FS-BLOG</h1>
</body>
</html>



Теперь нам нужно указать серверу, что при запросе на корневой роут, нам нужно запускать именно index.html

По сути - это сделать папку client публичной, статической. И когда мы будем делать запрос на сервер, то будем оказываться в папке client и по умолчанию отдавать файл index.html.

Для этого мы в файле арр подключим новый модуль path. Данный модуль входит в состав NodeJS и потому не требует дополнительной установки.

const path = require('path')

С помощью него можно очень удобно работать с разными путями.

Создадим новую переменную const clientPath, куда мы положим абсолютный путь до папки client. Воспользуемся методом join() модуля path.

В NodeJS есть глобальная переменная - __dirname, которая отвечает за абсолютный путь к текущей папке. Так, как мы сейчас в корневой папке нашего блока. то в __dirname мы получим абсолютный путь в папке fs-blog.

И чтобы теперь указать путь к папке client, нам нужно просто указать папку вторым параметром в методе join(). Вот так:

const clientPath = path.join(__dirname, 'client')

Теперь, когда мы получили путь до нужной нам папки, нам нужно сделать её статической.

Статической она делается довольно просто. После того, как мы с вами определим объект app, мы можем "оповестить" Экспресс о том. что хотим с помощью метода use(), добавить некий функционал серверу. Внутри метода указываем статическую, публичную папку. Для этого мы обращаемся к статическому методу экспреса и указываем путь до этой папки - clientPath:

app.use(express.static(clientPath))

Теперь, если мы будем делать запрос на сервер, он должен отдавать нам файл index.html.



Запуск рабочего процесса сервера - настройка окружения

Для остановки сервера нам приходится нажать Ctrl + C, потом ввест y и нажать Enter. Запуск его требует введения в КС:

npm run start


и опять Enter

Дело в том, что при внесении изменений в файлы, нам нужно постоянно перезапускать сервер, чтобы изменения вступили в силу (пересобрался сервер). делать это постоянно не очень удобно. Для того, чтобы сервер перезапускался автоматически после внесенных изменений мы установим пакет nodemon.

Чтобы его установить нам нужно ввести команду:

npm install nodemon -D


Enter

Здесь -D флаг, который указывает, что данная зависимость нужна нам только для разработки (development).

Проверим файл package.json. Там нас интересует поле


  "devDependencies": {
    "nodemon": "^1.18.4"
  }



Значит все прошло правильно. Остается только добавить еще один пользовательский скрипт в это файл:


  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },



Он будет делать тоже самое, что start но через пакет nodemon.

Теперь запуск сервера будет происходить командой:

npm run dev




База данных

Подключение MongoDB

Для этих целей нам потребуется локальный пакет mongoose, с помощью которого мы сможем делать очень удобные запросы к MongoDB. С помощью него мы сможем создавать модели, которые в последствии будут сущьностями в БД (база данных - здесь и далее.)

Установка пакета:

npm install mongoose


Есть разные возможности работы с БД - MongoDB. Можно её установить на компьютер локально. Плюсом такого подхода - это очень быстрое взаимодействие между сервером и БД. Минус - сложности установки MongoDB на комп. У всех разные системы, версии и пр. Для того, чтобы не отвлекаться на локальную установку, мы можем воспользоваться сервисом, который предоставляет полный API для MongoDB. Это сервис mLab.

Как можно предположить, это сервис который является удаленной версией MongoDB. Плюсы: простота использования, удобсвто настроек, бесплатно. Минусы - немного потеряем в скорости.

Нужно зарегистрироваться (создать аккаунт). Регистрация обычная. С подтверждением на почту.

Посте того, как залогинетесь появится окно с базами. Нам нужна кнопка - "Создать"



Выбираем Amazon и Бесплатную версию и нажимаем "Продолжить".



Выбрать точку поближе к себе на карте ( из предложеного и нажать "Продолжить"



Выбираем и вводим название:



Готовый чек - проверяем. Все действительно бесплатно и соглашаемся.



Происходит создание базы. Это может занять некоторое время и далее вы увидете:



База создана и готова к работе.

Переходим в нее (просто нажать на нее). и ...



Копируем эту строчку и возвращаемся в проект (редактор).

Давайте создадим некторую конфигурацию для наешего проекта, путем создания нового файла в корне приложения и назовем его keys.js

Здесь мы будем хранить некоторые константы, которые нужны для работы нашего приложения. Мы будем формировать здесь объект и экспортировать его наружу, чтобы другие файлы могли получать доступ к этим данным.


module.exports = {
	mongoURI: 'mongodb://<dbuser>:<dbpassword>@ds121413.mlab.com:21413/fs-blog'
}



Значением данного свойства мы вставили скопированную ссылку. В ней нам интересуют две вещи (отмечено красным).

Именно эти теги user и password нас интересуют.

Их нужно получить. В данном сервисе (mLab) нам нужно создать пользователя, который получит права доступа к БД. На записаь, на чтение и на удаление записей.

Выбираем "Users" "Add database user"



В сплывающем окне вводим имя и пароль. Галочку "read only" - НЕ СТАВИМ !

потому что мы хотим изменять базу данных

Данными имения и пароля мы заменяем теги user и password вместе с угловыми скобками.

После того, как мы получили ключи от БД мы идем в app.js и здесь мы подключаем mongoose


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



теперь в этом файле нам необходимо подключиться к MongoDB

Подключение к MongoDB.

Сделаем это после подключения констант. Для этого мы обращаемся к пакету mongoose и вызываем у него метод - connect(). Первым параметром нам нужно передать адрес БД к которой мы хотим подключиться. Для этого нам нужно подключить файл констант, подключить переменную keys из файла который лежит на одном уровне с файлом app.js, потому пишем './keys.js':

const keys = require('./keys')

.js можно не указывать, потому что NodeJS понимает, что по умолчанию это .js- файл.

Таким образом мы передаем первым параметром переменную keys.mongoURI

Метод connect() возвращает нам промис.

Мы можем использовать два метода .then() и .catch().

В случае успеха передадим в консоль 'MongoDB connected', а в случае неудачи выведем в консоль ошибку.


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
			.then(() => console.log('MongoDB connected'))
			.catch(err => console.error(err))	
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Запустим сервер

npm run dev


и в консоли увидим:



Теперь нам предстоит создать модель, для того, чтобы определить некоторую сущность в БД.

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

В корне проекта создадим новую папку, которая будет отвечать только за модели models.

Файлы этой папки (модели) в NodeJS принято называть с заглавной буквы.

Для работы с постом. создадим файл, в этой папке - Post.js

Теперь нам нужно описать модель, то есть какие сущьности будут у определенной модели в БД для поста.

первое что мы будем делать - это подключим mongoose, потому что с помощью него мы и будем описывать это все.

И далее. как это принято в мангусе. Мы создаем определенную схему, описываем поля,типы, описываем дефолтные значения, и после этого мы регистрируем нужную нам модель.

Первый шаг - это создание схемы!

Создание схемы

. Создаем переменную Schema она определяется из переменной mongoose и у нее есть класс Schema.

const Schema = mongoose.Schema

Теперь мы создаем схему нашего поста то есть - описание модели. Назовем её postSchema, например.

Она является экземпляром класса Schema, где в конструктор мы передаем объект конфигурации.

Давайте решим. что у нашего поста может быть?


 const mongoose = require('mongoose')

 const Schema = mongoose.Schema

 const postSchema = new Schema({
 	
 })



Во-первых - уникальный id, но его будет выдавать сама БД (MongoDB), поэтому нам его описывать необязательно.

У поста будет название, текст и дата создания.

Начнем с описания названия поста. Допустим, что это будет title и это объект. Так как мы описываем схему.

Какого типа будет у нас заголовок? Мы описываем его как строку - String и говорим, что заголовок для каждого поста нам нужен обязательно :


 const postSchema = new Schema({
 	title: {
 		type: String,
 		required: true
 	}

 })



Далее описываем контент поста - точно так же.

Еще одно поле date - дата когда был создан пост. По сути, было бы логично, если бы сервер при создании поста сделал это за нас.

Тип переменной будет Date, потому что мы будем работать с датой. И так как сервер у нас будет сам выдавать дату создания, то вместо флага required - default

default: Date.now

Важно без скобок, чтобы не вызывать эту функцию.

С помощью метода мы экспортируем наружу данную модель и экспортируем мы результат регистрации данной модели в базе. То есть говорим mongoose о том, что с помощью метода model() мы хотим зарегистрировать в БД новую коллекцию - posts и модель каждого поста будет являться схемой которую мы создали.

module.exports = mongoose.model('posts', postSchema)

Файл Post.js


 const mongoose = require('mongoose')

 const Schema = mongoose.Schema

 const postSchema = new Schema({
 	title: {
 		type: String,
 		required: true
 	},
 	text: {
 		type: String,
 		required: true
 	},
 	date: {
 		type: Date,
 		default: Date.now
 	}

 })

 module.exports = mongoose.model('posts', postSchema)



База подключена и осталось разработать на сервере роуты, которые будут работать с разными постами.





                                                                                                                                                             

пятница, 1 июня 2018 г.

Скрыть / Показать содержимое поля ввода.

Довольно часто бывает необходимость добавить некий функционал полю ввода. Например - срыть / показать пароль пользователю, при вводе данных. Это значительно облегчает введение данных, особенно в случаях неисправности клавиатуры пользователя (западают кнопки, не пропечатываются, или не работает Caps или Shift.В общем, вещь не только привлекательная, но и порой, даже нужная!




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

Без долгих предисловий.

Рассмотрим вариант самого простого функционала - просто показать / скрыть пароль кликом на кнопку:

Вариант 1:самый простой.


Меняется только надпись на кнопке.
В файле HTML ничего особенного. Просто поле ввода пароля и кнопка. Им добавлены идентификаторы - id, для того, чтобы можно было с ними работать при помощи JavaScript.

JavaScript код я не стал выносить в отдельный файл и записал его здесь же.

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

На кнопку вешаем событие - click и запускаем функцию.

Внутри функции мы проверяем значение атрибута type у элемента input. Если это password, то мы меняем его на атрибут text, и наоборот.

Заодно и поменяли одержимое (название) кнопки button.

Можно это не делать, если не хотите добавлять достаточно затратную операцию .innerHTML. Для этого достаточно удалить код отмеченный красным.

Ниже полностью код файла index.html

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>

</head>
<body>
 <p>Enter the Password: <input type="password" id="show1"></p>
 <button id="show">Show password</button>

 <script>
  var input = document.getElementById("show1");
  var button = document.getElementById("show");
  button.onclick = show;

  function show () {
   if(input.getAttribute('type') == 'password') {
    input.removeAttribute('type');
    input.setAttribute('type', 'text');
    button.innerHTML='Hide password';

   } else {
    input.removeAttribute('type');
    input.setAttribute('type', 'password');
    button.innerHTML='Show password';

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


Вариант с иконкой.


Смена надписи на кнопке и иконки в любой части кода

Идем на сайт Font Awesome и выбираем понравившиеся иконки.

Подключаем Font Awesome через CDN в нашем хедере.

Добавляем одну иконку на страницу.

Например: <i id="i" class="far fa-eye"></i>

Теперь мы будем менять не только атрибут, но и класс элемента i, поэтому нам нужно добавить элементу идентификатор id

Остальное здесь все почти точно так же.

Ниже полностью код файла index.html


        <!DOCTYPE html>
 <html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>Document</title>
  <!-- Font - Awesome -->
   <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
 </head>
 <body>
  <!-- <i class="far fa-eye-slash"></i> вторая иконка закомментированна-->
  <p>Enter the Password: <input type="password" id="show1"></p>
  <button id="show">Show password</button><i id="i" class="far fa-eye"></i>
  
  <script>
   var button = document.getElementById("show");
   button.onclick = show;
   var input = document.getElementById("show1");
   var icon = document.getElementById("i");
   function show () {
    if(input.getAttribute('type') == 'password') {
     input.removeAttribute('type');
     input.setAttribute('type', 'text');
     button.innerHTML='Hide password';
     icon.className = 'far fa-eye-slash';
    } else {
     input.removeAttribute('type');
     input.setAttribute('type', 'password');
     button.innerHTML='Show password';
     icon.className = 'far fa-eye';
    }
  }
 </script>
 </body>
 </html>



Несомненный плюс этого метода, это то, что иконку можно разместить в любой части сайта. Все примеры, я намеренно привожу без CSS, потому как это добавит вам простор для различных способов стилизации и оформления документа.

В этом коде все будет работать так как показано на картинке, но стоит помнить, что класс мы меняем новым свойством браузера, которое не поддерживается браузером IE < 10 версии.



В таких случаях можно использовать jquery или вариант ниже.

Третий вариант



Смена надписи и иконки внутри кнопки

Этот вариант вообще простой и очень похож на первый, потому что мы здесь меняем только содержимое кнопки кодом .innerHTML, куда мы положили и наши иконки.

Ниже полностью код файла index.html


 <!DOCTYPE html>
 <html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>Document</title>
  <!-- Font - Awesome -->
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
  <!-- your file js -->
  <script src="main.js" defer></script>
 </head>
 <body>

  <p>Enter the Password: <input type="password" id="show1"></p>
  <button id="show">Show password  <i id="i" class="far fa-eye"></i></button>
  
  <script>
   var button = document.getElementById("show");
   button.onclick = show;
   var input = document.getElementById("show1");
   var icon = document.getElementById("i");
   function show () {
    if(input.getAttribute('type') == 'password') {
     input.removeAttribute('type');
     input.setAttribute('type', 'text');
     button.innerHTML='Hide password  <i id="i" class="far fa-eye-slash">';
    } else {
     input.removeAttribute('type');
     input.setAttribute('type', 'password');
     button.innerHTML='Show password  <i id="i" class="far fa-eye">';
    }
   }
  </script>
 </body>
 </html>





Вариант с подменой вводимых символов.

Приведу такой вариант просто для информации. Если честно, то совершенно не могу представить, где он может пригодиться.

Суть в том, что мы можем сохранить то что вводит пользователь так как ест, а вместо этого подставить в поле ввода случайные символы.

То есть. Пользователь вводит, например - vvvvvvvvv, а в поле ввода видит - ZfhEysUFKk.
Точно. как на картинке ниже.



Для этого мы сохраняем то что ввел пользователь в переменную str, а вместо этого в this.value выводим случайный символ, полученный путем генерации случайного числа (от 65 до 122 - потому как это цифровое значение символов в разных регистрах разрешенных для паролей).

Затем, мы из случайного числа генерируем символ - String.fromCharCode(); И уже этот символ выводим в поле ввода присвоив его переменной this.value Здесь приведу сам js скрипт


        var str =  "";  // то что ввел юзер
 document.getElementById("test").onkeypress = function (event) {
  // то что ввел юзер
  // var str = this.value;
  str = str + event.key;
  console.log(str);

  // вывод в инпут случайных символов
  this.value += String.fromCharCode(getRandomInt(65, 122));
  // запрет вывода в инпут того что вводит пользователь 
  return false;
 }
 // функция генерации случайного числа от - до
 function getRandomInt(min, max) {
   return Math.floor(Math.random() * (max - min)) + min;
 }



                                                                                                                                                             

воскресенье, 8 апреля 2018 г.

Bootstrap 4 SASS .Руководство.

Выход новой версии Bootstrap4 подтолкнул меня к написанию этого руководства, потому что новая версия значительно отличается. На изучение её придется потратить некоторое количество времени, но оно того стоит. Данное руководство не является полным путеводителем по Bootstrap4, и несомненно, вам придется еще не раз заглянуть в документацию, но здесь мы рассмотрим базовые вещи по созданию макета сайта на bootstrap4 двумя различными способами

Установка

В нашем случае мы будем использовать SASS и поэтому воспользуемся полной установкой.

Если вам просто нужен Bootstrap для быстрого прототипирования, имеет смысл использовать метод CDN. Вы просто подключаете файлы, которые находятся на других ресурсах в интернете, без установки (скачивания). Таким образом вы добавляете их в ваш проект в виде ссылок.

Вы можете просто добавить код из примера ниже, в ваш файл проекта - index.html

<!doctype html> 
<html lang="en"> 
  <head> 
    <meta charset="utf-8"> 
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 

    <!-- Bootstrap CSS --> 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> 

    <title> Bootstrap 4 Starter Template</title> 
  </head> 
  <body> 
    <h1> Hello< /h1> 

    <!-- Optional JavaScript --> 
    <!-- jQuery first, then Popper.js, then Bootstrap JS --> 
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"> </script> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"> </script> 
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"> </script> 
  </body> 
</html> 


Этот код прямо из страницы начальной загрузки Bootstrap 4.

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

Установка Bootstrap 4 через NPM

Мы собираемся начать наш проект прямо здесь, на этом этапе. Это потребует использования Node.js и его менеджера пакетов для установки самого загрузочного устройства вместе с несколькими другими пакетами. Это даст нам доступ к Sass, перезагрузке в реальном времени и т.д.

Во-первых, убедитесь, что вы установили Nodejs, открыв консоль или командную строку:

node -v

Если вы получите значение текущей версии, то все в порядке и можно продолжать, а если нет, то загрузите соответствующий установщик на основе вашей ОС и выполните процедуру установки с настройками по умолчанию.

Некоторые полезные сведения по настройке вы можете прочитать в моем посте - NPM Настройка Gulp и компиляции SASS

После завершения установки, перезагрузите консоль или командную строку, и у вас будет доступ к командам Node.js.

Давайте создадим папку для нашего проекта и перейдем в нее:

mkdir bs4 && cd bs4

Затем мы запустим npm init, чтобы создать файл package.json, который просто хранит наши зависимости.

npm init -y

(Примечание. Флаг -y просто позволяет нам пропускать ответы на различные запросы и вместо этого предоставляет им значения по умолчанию)

Затем мы снова будем использовать npm для установки нескольких разных пакетов в зависимости от зависимостей разработки:

npm install gulp browser-sync gulp-sass --save-dev

Здесь:

  1. Gulp— это таск-менеджер для автоматического выполнения часто используемых задач.Вы увидите, как это работает, если вы новичок.
  2. Brows-sync автоматически обновляет ваш браузер для нас при изменении файла.
  3. gulp-sass позволяет собирать наш проект, интегрируя его с sass.
  4. --save-dev - установить в отдельную папку. В нашем случае в папку проекта т.е - локально.


Затем мы будем использовать npm в последний раз, чтобы установить несколько пакетов в качестве регулярных зависимостей проекта:

npm install bootstrap jquery popper.js --save

  1. bootstrap - конечно же, это пакет начальной загрузки.
  2. jquery - java script библиотека, используемая непосредственно самим bootstrap шаблоном
  3. popper.js также используется бутстрапом. Он позволяет размещать всплывающие окна, всплывающие подсказки и т.д.


Теперь, настало время открыть наш проект в редакторе кода. Я буду использовать Sublime 3.

Мы должны создать папку src для нашего проекта и несколько вложенных в нее папок. Дерево выглядит так:

/src
    /assets
    /css
    /js
    /scss


Внутри / src также создайте 4 папки, как показано выше.

Затем создайте файл index.html внутри / src / со следующим содержимым:

<!DOCTYPE html> 
<html class="no-js" lang="en"> 
    <head> 
        <title> Bootstrap 4 Layout< /title> 
        <meta http-equiv="x-ua-compatible" content="ie=edge"> 
      < meta name="viewport" content="width=device-width, initial-scale=1.0" /> 

        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway:400,800"> 
        <link rel='stylesheet' href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> 
        <link rel="stylesheet" href="/css/bootstrap.css"> 
        <link rel="stylesheet" href="/css/styles.css"> 
    < /head> 

    < body> 
        <script src="/js/jquery.min.js"> </script> 
        <script src="/js/popper.min.js"> </script> 
        <script src="/js/bootstrap.min.js"> </script> 
    < /body> 
< /html> 


Я импортирую шрифт Raleway вместе с FontAwesome для иконок. Затем я ссылаюсь на bootstrap.css и файл styles.css. Они еще не существуют, но мы скоро их создадим.

Давайте также создадим файл styles.scss внутри папки / src / scss /. Мы собираемся ввести быструю переменную и набор правил для того, чтобы убедиться, что компиляция Sass работает:

$bg-color: red; 

body {
    background: $bg-color;
}


В корневой папке (папке проекта) создайте файл gulpfile.js и вставьте следующее содержимое:

var gulp        = require('gulp');
var browserSync = require('browser-sync').create();
var sass        = require('gulp-sass');

// Compile sass into CSS & auto-inject into browsers
gulp.task('sass', function() {
    return gulp.src(['node_modules/bootstrap/scss/bootstrap.scss', 'src/scss/*.scss'])
        .pipe(sass())
        .pipe(gulp.dest("src/css"))
        .pipe(browserSync.stream());
});

// Move the javascript files into our /src/js folder
gulp.task('js', function() {
    return gulp.src(['node_modules/bootstrap/dist/js/bootstrap.min.js', 'node_modules/jquery/dist/jquery.min.js', 'node_modules/popper.js/dist/umd/popper.min.js'])
        .pipe(gulp.dest("src/js"))
        .pipe(browserSync.stream());
});

// Static Server + watching scss/html files
gulp.task('serve', ['sass'], function() {

    browserSync.init({
        server: "./src"  
    });

    gulp.watch(['node_modules/bootstrap/scss/bootstrap.scss', 'src/scss/*.scss'], ['sass']);
    gulp.watch("src/*.html").on('change', browserSync.reload);
});

gulp.task('default', ['js','serve']);


Я опишу, что здесь происходит, исходя из задач, определенных выше:

  1. default task - задача по умолчанию. Когда мы вводим gulp в командной строке, это говорит ему запускать как js, так и обслуживать задачи - task.
  2. js task Это просто указание трех разных файлов javascript, которые хранятся в папке node_modules, которая создается при запуске npm install ... и перемещении их в нашу папку / src / js. Таким образом, мы можем включить их в наш HTML-файл выше, указав / src / js вместо папки node_modules.
  3. serve task запускает простой сервер и наблюдает за нашими sass-файлами, и если они меняются, он вызывает задачу sass. Он также вызывает синхронизацию браузера при сохранении любого * .html-файла.
  4. sass task Эта задача берет файлы bootstrap sass, так и наши пользовательские sass-файлы и компилирует их в обычный CSS, и сохраняет эти файлы CSS в нашей папке / src / css


Теперь настройку можно считать законченной.

Давайте запустим gulp в командной строке:

gulp

В любом случае, http: // localhost: 3000 загрузится в браузере, и ваш фон будет ярко красным! Это означает, что все прошло хорошо.

Контейнер для гридов

Начальная точка вашего проекта Bootstrap 4 почти всегда будет вращаться вокруг контейнера сетки. Класс .container позволяет горизонтально центрировать ваш макет. В качестве альтернативы, для макета .container-fluid. (100% -ная ширина), вы можете использовать .container-fluid.

Итак, давайте определим контейнер сетки как самый первый элемент в нашем макете:

    <body> 
        <div class="container"> 
            test
        </div> 

        ...3 тега сценария опущены
    </body> 


Кроме того, удалите все из ваших styles.scss, поскольку нам не нужен красный фон.

Если вы посмотрите на своем браузере в инспекторе (CTRL+SHIFT+i в Chrome) на этот макет, то нажмите на значок селектора элементов и наведите указатель мыши над текстом «test», вы увидите контур контейнера. Это гибкий контейнер, поэтому вы можете уменьшить ширину вашего браузера и наблюдать, как он реагирует.

Определение Bootstrap 4 Navbar

После определения контейнера следующая наиболее вероятная секция раздела вашего макета, вероятно, будет какой-то навигацией. В Bootstrap это называется navbar.

Примечание. Ознакомьтесь с документацией Navbar. Документация для каждого элемента Bootstrap 4 довольно полная. Он предоставляет вам примеры вместе с соответствующим кодом.

Большинство навигационных панелей включают логотип компании, обычно выравниваемый по левому краю. Мы также будем включать навигацию, которая выровнена по правому краю.

Внутри нашего элемента .container добавим следующее:

<div class="container"> 
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> 
        <a class="navbar-brand" href="#"> CompanyName< /a> 
        
        <div class="collapse navbar-collapse" id="navbarSupportedContent"> 
            <ul class="navbar-nav ml-auto"> 
                <li class="nav-item"> 
                    <a class="nav-link" href="#"> Home</a> 
                </li> 
                <li class="nav-item"> 
                    <a class="nav-link" href="#"> About</a> 
                </li> 
                <li class="nav-item"> 
                    <a class="nav-link" href="#"> Products</a> 
                </li> 
                <li class="nav-item"> 
                    <a class="nav-link" href="#"> Contact</a> 
                </li> 
            </ul> 
        </div> 
    </nav> 
</div> 


Результат в браузере на этом этапе должен соответствовать следующему:



Как вы можете видеть, простой заголовок с навигацией. Для элемента списка продуктов, давайте изменим его так, чтобы он стал выпадающим меню:

<li class="nav-item dropdown"> 
    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" data-toggle="dropdown"> 
        Products
    </a> 
    <div class="dropdown-menu"> 
        <a class="dropdown-item" href="#"> Product 1</a> 
        <a class="dropdown-item" href="#"> Product 2</a> 
        <div class="dropdown-divider"> </div> 
        <a class="dropdown-item" href="#"> Another Product</a> 
    </div> 
</li> 


Результат должен выглядеть следующим образом:



В настоящее время наша навигационная система не имеет кнопки на мобильных устройствах. Итак, мы должны добавить HTML-код, необходимый для работы.

Добавьте следующую разметку между брендом и навигационным содержимым div:

<a class="navbar-brand" href="#"> CompanyName</a> 

<!--Add here --> 
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"> 
    <span class="navbar-toggler-icon"> </span> 
</button> 
<!--Add here --> 

<div class="collapse navbar-collapse" id="navbarSupportedContent"> 


После сохранения перетащите свой браузер в мобильное окно просмотра и нажмите кнопку переключения. Результат должен быть похож на следующий:



Как вы можете видеть, невероятно просто построить надежную, отзывчивую навигацию с помощью Bootstrap 4.

Интеграция раздела Bootstrap 4 (Секция Jumbotron)

Следующий общий элемент для многих макетов и целевых страниц - это раздел Jumbotron.

Под контейнером <nav> .. </ nav> добавьте следующий HTML:

...
</nav> 

<!-- Add here --> 

<div class="jumbotron"> 
    <h1 class="display-4"> Simple. Elegant. Awesome.</h1> 
    <p class="lead"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p> 

    <p class="lead"> 
        <a class="btn btn-primary btn-lg" href="#" role="button"> Learn more</a> 
    </p> 
</div> 


Большая часть этого HTML была взята из документации Jumbotron, но я просто модифицировал и удалял некоторые элементы, соответствующие моим потребностям. По большей части вы можете сделать это для любого другого необходимого элемента Bootstrap 4, так как их документация предоставляет вам множество примеров.

Результат в браузере теперь должен выглядеть так:



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

Система сеток Bootstrap 4

Возможно, самым важным аспектом, который следует понимать, когда речь идет о BS 4, является система сетки. Это основано на Flexbox, и если вам интересно, нет - сетка в BS 4 не основана на новой сетке CSS, к сожалению.

Bootstrap 4 был разработан уже много лет, и они уже были посвящены Flexbox. На данный момент Flexbox является более безопасной ставкой, поскольку сетка CSS поддерживается 76% браузеров, а Flexbox - почти на 100%.

Сетка Grid Documentation очень детализирована с множеством опций и примеров. Обязательно обратитесь к этой странице, когда у вас есть определенные потребности.

Для наших целей изначально мы собираемся определить раздел в нашем макете, который будет иметь 3 столбца равной ширины. Внутри этих столбцов у нас будут только некоторые функции, связанные с нашей компании. Мы собираемся использовать карты Bootstrap 4 для внутреннего содержимого внутри каждого из этих столбцов:

<div class="row"> 
    <div class="col"> 
        <div class="card"> 
            <div class="card-body text-center"> 
                <h5 class="card-title"> Card title</h5> 
                <p class="card-text"> Some quick example text to build on the card title</p> 
                <a href="#" class="card-link"> Another link</a> 
            </div> 
        </div> 
    </div> 
    <div class="col"> 
        <div class="card"> 
            <div class="card-body text-center"> 
                <h5 class="card-title"> Card title</h5> 
                <p class="card-text"> Some quick example text to build on the card title</p> 
                <a href="#" class="card-link"> Another link</a> 
            </div> 
        </div> 
    </div> 
    <div class="col"> 
        <div class="card"> 
            <div class="card-body text-center"> 
                <h5 class="card-title"> Card title</h5> 
                <p class="card-text"> Some quick example text to build on the card title</p> 
                <a href="#" class="card-link"> Another link</a> 
            </div> 
        </div> 
    </div> 
</div> 


Это результат в браузере:



Это все столбцы с одинаковой шириной, которые достигаются путем простого указания класса .col на каждый столбец.

Если вы хотите, чтобы один из этих трех столбцов имел большую ширину, вы можете указать .col- # (# от одного до 12):

<div class="row"> 
    <div class="col"> 
        ...
    </div> 
    <div class="col-6"> 
        ...
    </div> 
    <div class="col"> 
        ...
</div> 


И сетка автоматически отрегулирует ширину остальных столбцов так:



Мы не хотим этого. Таким образом, вы можете удалить -6 из среднего столбца.

Прямо сейчас, если вы настроите браузер на мобильный вид, вы увидите, что наша сетка не реагирует; они остаются в 3 колонках.

Скажем, например, что мы хотим, чтобы наша первая карта в первом столбце охватывала 100% ширину окна просмотра (предположим все 12 столбцов) только в небольших видовых экранах:

<div class="row"> 
    <div class="col-sm-12 col-md-4"> 
        <div class="card"> 

Сначала мы указываем .col-sm-12, что означает, что в небольших видовых экранах этот столбец займет все 12 столбцов.

Затем мы указываем .col-md-4, что означает, что на средних видовых экранах и больше он будет принимать 4 столбца:



Существует, конечно, гораздо больше вариантов и со временем вы сможете узнать о сетке Bootstrap 4 намного больше, но это общий смысл.

Вы можете использовать множество классов сетки для определения количества строк, которые должен принимать столбец в данном окне просмотра.

Отступы - Margins и Padding в Bootstrap 4

Обратите внимание, что в нашем примере изображение выше, между нашими элементами карты нет разницы? Если вам когда-либо понадобится добавить маркер (пространство вне элемента) или дополнение (пространство внутри элемента), вы можете использовать вспомогательные классы полей и дополнений.

Это работает следующим образом:
  • Вы используете m для margin или p для padding
  • После m или p вы добавляете либо: t (top - ), b (bottom -снизу), l (left -слева), r (right-cправa), x (левый и правый), y (верхний и нижний) или ничего для всех 4 сторон.
  • После дефиса вы указываете размеры от 0 до 5 (5 - наибольшее количество интервалов).


Итак, в нашем примере, похоже, нам нужно использовать margin и bottom , чтобы оттолкнуть карты под ним.

На первом карточном контейнере добавьте mb-4:

<div class="card mb-4">


Теперь исправлено:



Вот как вы можете легко обрабатывать оба поля и отступы в Bootstrap 4.

Давайте немного поработаем с использованием различных компонентов Bootstrap 4.

Работа с «Типографией» в Bootstrap 4

Давайте добавим раздел под нашими 3 столбцами в конце закрывающего </ div> для класса строк, который будет иметь 2 столбца.

Первый столбец будет использовать большинство столбцов (8), а правый столбец будет для вертикальной навигации в секции после этого.

<div class="row mt-sm-4 mt-md-0"> 
    <div class="col-sm-12 col-md-8"> 
        <h3> An important heading</h3> 
        <p class="lead"> A sort of important subheading can go here, which is larger and gray.</p> 

        <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> 
        <p> Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> 
    </div> 

    <div class="col-sm-12 col-md-4"> 
        ..vertical navigation shortly..
    </div> 
</div> 


Bootstrap 4 имеет раздел «Типография» в своей Документации, который предоставит вам все вспомогательные классы на основе типа. Это довольно просто. Мы используем .lead, чтобы сделать акцент на подзаголовке под нашим элементом h3.

В своей Документации также есть раздел «Утилиты текста», который предоставляет вам параметры выравнивания текста, преобразования, курсив и веса шрифтов.

В небольших видовых экранах предположим, что мы хотим, чтобы наш тип был центрирован, а не по умолчанию, который выравнивается по левому краю.

Мы добавили бы следующий класс:

<div class="col-sm-12 col-md-8 text-sm-center text-md-left">


Это приведет к тому, что текст, содержащийся в div, будет сосредоточен в центре на небольших видовых экранах и выровнен по левому краю на среднем и большем.

Bootstrap 4 Вертикальная навигация

Мы добавим еще один элемент, прежде чем мы займемся настройкой. В нашей правой колонке, которую мы только что добавили, добавим вертикальную навигацию:

    <div class="col-sm-12 col-md-4"> 
        <h3 class="mb-4"> Secondary Menu</h3> 

        <ul class="nav flex-column nav-pills"> 
            <li class="nav-item"> 
                <a class="nav-link active" href="#"> Active</a> 
            < /li> 
            <li class="nav-item"> 
                <a class="nav-link" href="#"> Link</a> 
            </li> 
            < li class="nav-item"> 
                <a class="nav-link" href="#"> Link</a> 
            </li> 
            < li class="nav-item"> 
                <a class="nav-link disabled" href="#"> Disabled</a> 
            </li> 
        </ul> 
    </div> 


Результат в браузере должен выглядеть так:



Вы также можете проверить его на небольших видовых экранах и заметить, что он отлично реагирует. Есть, конечно, гораздо больше возможностей, связанных с навигацией.

Кастомизационная настройка в Bootstrap 4

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

К счастью, Bootstrap 4 имеет прочную систему, которая позволяет легко настраивать простые элементы.

Откройте файл /src/scss/styles.scss и вставьте следующее:

// Variable Overrides 

// Bootstrap Sass Imports
@import "node_modules/bootstrap/scss/bootstrap";


Согласно разделу Theming, вы можете выбрать либо включить все файлы Bootstrap 4 sass, либо добавить отдельные элементы в зависимости от ваших потребностей. Чтобы все было просто, мы просто импортируем все, как было выше.

Изменение цветов темы в Bootstrap 4

Возможно, наиболее распространенной проблемой является изменение цвета.

Если вы откроете файл node_modules / bootstrap / scss / _variables.scss, вы заметите, что в верхней части он упоминает систему цветов. В этом разделе вы увидите все переменные, которые вы можете переписать, чтобы соответствовать цветам.

Давайте изменим только основной цвет, изменим styles.scss на следующее:

// Variable Overrides 
$theme-colors: (
  "primary": #d95700
);


Сохраните его, и это результат:



Очень просто!

Давайте также изменим цвет фона:

// Variable Overrides 
$theme-colors: (
  "primary": #d95700
);

$body-bg: #ededed;


Теперь результат выглядит следующим образом:



Хм, теперь наша секция jumbletron (hero) выглядит уродливой, так как она также была серой.

Мы можем настраивать пользовательские настройки для определенных элементов, используя инспектор в chrome или firefox, находим связанные классы элементов, которые хотим изменить, и изменяем их в нашем файле styles.scss.

В этом случае класс, ответственный за jumbotron, является .jumbotron. Давайте изменим цвет фона и добавим небольшую границу к вершине, чтобы имитировать dropshadow из navbar:

// Variable Overrides 
$theme-colors: (
  "primary": #d95700
);

$body-bg: #ededed;

.jumbotron {
    background-color: #ffffff !important;
    border-top: 3px solid rgb(219, 219, 219);
}


Теперь результат:



Заключение

Надеюсь, вам понравился этот курс / учебник по Bootstrap 4. Мы только слегка коснулись основ, и есть еще много чего вы можете узнать. На этом этапе все, что вам нужно изучить, должно быть простым, так как теперь вы понимаете основы и что почти все описано в документации.

Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.


Удачного кодирования!




Выражаю огромную благодарность Gary Simon за его труд и доступную подачу материала.
                                                                                                                                                             

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com