Translate

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

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

четверг, 4 октября 2018 г.

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





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


Создание REST API роутов

В корне проекта создадим папку - routes.

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

В файле сразу подключаем express - const express = require('express')

Далее создадим переменную, которая добывается из функции экспресс - Router()

const router = express.Router()

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

module.exports = router

Пока мы не пишем здесь никакого функционала. Давайте попробуем его применить для нашего сервера.

Для этого мы должны перейти в файл app.js, где мы описываем сервер и подключит данный роутер.

const postRouter = require('./routes/post.js').


const express = require('express')
const mongoose = require('mongoose')
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(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Теперь, для того чтобы использовать наш роутер, мы должны, после того, как определили объект нашего приложения =>const app = express() (ниже) написать команду

app.use('', postRouter)

Для того чтобы применить какой то роут и экспресc понимал ссылки.

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

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

Теперь нужно подумать какой префикс нам здесь написать?

По сути, у нас будет часть сервера, которая будет отдавать клиентскую сторону - index.html и у нас будет часть сервера, которая будет отвечать за REST API. Соответственно, все что будет делаться через REST API мы можем начинать с префикса /api/ и далее, так как у нас идет здесь идет работа именно с постами, мы можем указывать сущьности - например post

app.use('/api/post', postRouter)

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

Перейдем в файл post.js

По сути для нашего приложения важно реализовать три действия:
  1. - получит все посты, которые есть в БД
  2. - создать новый пост
  3. - реализовать удаление какого-то поста
В REST API для того, чтобы получать что-то мы используем http-запросы с методом get.

Для того, чтобы реализовать метод get в экспрессе мы обращаемся к роутеру (router) и вызываем у него метод get.

Здесь в качестве параметра мы просто указываем слэш - '/'.

Вторым параметром указываем callback-функцию, которая принимает два параметра ( req -request - запрос res - response - ответ.)

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


router.get('', (req, res) => {
	
})



Теперь давайте посмотрим. что это будет за роут и как он будет определяться.

У нас есть некоторый префикс - '/api/post' и это означает, что мы будем видеть запрос следующего характера:

http://localhost:5000/api/post

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

Похожая ситуация у нас будет реализована еще для двух методов.

В REST API если мы хотим что-то создать, то мы используем метод POST, удалить - DELETE.

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

routes/post.js


const express = require('express')

const router = express.Router()
// http://localhost:5000/api/post GET
router.get('', (req, res) => {

})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Сейчас, давайте попробуем описать метод GET с помощью которого мы хотим что-то получить.

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

const Post = require('../models/Post')

Теперь с помощью этого объекта мы уже можем работать с БД.

Для того, чтобы получить все сущьности из БД, нам нужно в методе GETобратиться к и вызвать у него метод find(), передав в метод пустой объект. Это означает, что мы будем требовать все посты без каких либо условий.


router.get('', (req, res) => {
	Post.find({})
})



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


router.get('', (req, res) => {
	Post.find({}).then((posts)=>{
 	//что-то делать...	
 })
})



Мы пойдем более современным путем. Так как мы работает на платформе NodeJS, которая не требует понимания разных браузеров, то здесь можно использовать все новшества современного JS ES6.

Поэтому мы смело можем использовать синтаксис - async/await.

Вместо того, чтоб так ченить промисы.

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

И теперь, чтобы получить список этих постов, мы можем просто создать переменную posts и с помощью префикса await - подождать.

const posts = await Post.find({})

Эта конструкция полностью идентична

	Post.find({}).then((posts)=>{
          // ...
	})



При этом мы написали полностью асинхронный код и у нас нет вложенных функций.

Таким образом мы получили:


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
const posts = await Post.find({})
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Думаем над тем. что нам делать еще в методе GET По сути, мы должны что-то отдать клиенту (список постов). Для того, чтобы ответить клиенту мы можем воспользоваться объектом res, затем указать статус

res.status(200) и с помощью метода json указать те данные, которые мы хотим отправить обратно - posts.

res.status(200).json(posts)


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Коротко: мы просто ждем, что сто-то придет к нам с базы данных и после этого отправляем их клиенту.

Метод POST

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

Создадим переменную postData и это будет объект с полями title и text. Здесь мы будем с клиента отправлять данные в БД. Для сбора данных и нужны эти поля.

Теперь эти данные нужно обработать. Это сделать просто. У нас есть объект req с помощью которого будет сделан запрос и сказать ему, что например, title хранится в req.body.title.


router.post('', (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
})



Теперь у нас есть данные необходимые для создания нового поста в базе и мы можем создать новый пост с помощью модели Post на основе данных postData.

const post = new Post(postData)

И после этого нам нужно сохранить это все в БД. Для этого можно просто написать:

await post.save()

И сделать функцию асинхронной:


router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
})



Этой строкой -

await post.save()

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

И теперь мы можем ответить (res)клиенту оперируя теми данными, которые мы получили с БД.

В RESTAPI если мы что-то создаем, то используем статус 201, а далее методом json мы указываем. чо будем обратно возвращать post.

res.status(201).json(post)


// http://localhost:5000/api/post POST
router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})



Метод DELETE

Он будет тоже асинхронным, как и предыдущие методы. (Добавим async).

В этом методе нам нужно будет удалить пост по ID. Поэтому здесь уже не подойдет такой url - http://localhost:5000/api/post, потому что нам в нем надо передать id того поста, который мы хотим удалить. Например id =34;

http://localhost:5000/api/post/34

Эта часть будет динамическая.

Для того, чтобы указать какую-либо динамическую часть в Экспрессе, нам достаточно поставить после слэша двоеточие и написать id.

Именно так - id будет называться параметр, который мы будем получать в этом месте.

Теперь нам нужно с помощью модели Post вызвать метод remove(), который позволяет нам что-то удалять из базы. и далее мы говорим условия - какой именно пост мы хотим удалить в объекте. Мы хотим удалить пост у которого _id === id который придет в роуте. А этот параметр хронися в объекте запроса req (req.params.is)

Так как функция асинхронная, то мы ее должны подождать - await


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
})



Как только удалится нужный нам пост мы можем ответить клиенту статусом 200 и в json отправить мессендж -"Удалено"


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})



Теперь наш роутер, который работает с сущностями поста полностью готов.

Файл post.js


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('/', async (req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('/', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})
// http://localhost:5000/api/post DELETE
router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})

module.exports = router



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

Тестирование серверной части.

Всё, что относится к фронтенд части хранится в папке client. Там, пока что, один файл - index.html

Начнем с верстки. На ней я подробно останавливаться не буду. Отмечу только, что для адаптивности и простоты я использовал фреймворк Materialize.

Подключаем css, material icons и скрипт js к нашему index.html файлу через CDN (ссылки на сайте) . После скрипта материалайза подключаем наш скрипт index.js, который мы создадим в той же папке.

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

В файле index.html создадим div - контейнер, которому зададим стиль, чтобы он не прилипал к верху экрана и в него мы будем выводить посты.


<!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="post">
				<div class="card">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</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>



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

npm run dev


Переходим на сайт localhost:5000 и видим:



Теперь перейдем к клиентскому скрипту и посмотрим как вывести список всех постов.

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


<!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="post">
		<div class="card z-depth-4">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</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>



И так как здесь у нас нативный JS, то мы создадим подобие компонента в переменной card


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>
	`
}



Функция, которая принимает post и отдает html разметку. Данные в которой мы выводим как переменные.

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

Для этого нам потребуется некоторый инструмент с помощью которого мы будем делать запросы.

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

Допустим, что это будет класс PostApi. У него будет несколько методов.

Первый статический static fetch(), в который мы не будем передавать параметры. Этим методом мы будем делать запрос на получение всех наших постов.

В JS есть нативная функция fetch(), с помощью нее мы как раз и можем делать запросы.

Первым параметром в эту функцию нам надо передать url по которому мы хотим сделать запрос.

Для этого мы создадим новую константу - const BASE_URL='api/post' - Это та самая строчка. которая обозначена в файле app.js.

Вторым параметром мы указываем метод с помощью которого мы хотим сделать запрос. В нашем случае, когда мы хотим получить список всех потов это метод GET. ({method: get}.

Далее, метод fetch() возвращает промис и в методе .then мы можем привести тот формат который прилетает к нам с сервера и обрабатывается JS, привести в понятный формат объектов. Поэтому - res=>res.json() и все это вернем из метода fetch().


const BASE_URL = '/api/post'

clss PostApi {
	static fetch(){
		return fetch(BASE_URL, {method: get}).then(res=>res.json())
	}
}



И теперь в какой момент нам необходимо сделать запрос?

При загрузке страницы.

На документ поставим обработчик события.

document.addEventListener('DOMContentLoaded', () => {
	
})


Как только запускаем приложение нам нужно сделать запрос к бекенду, поэтому мы обращаемся к PostApi.fetch и вызываем метод .fetch() и так как он возвращает промис, то .then(). В этом методу мы будем получать объект backendPosts. То есть это будет уже тот массив, который прилетит от сервера. И теперь, нам нужно просто вывести все эти посты в html.

Для этого создадим наверху файла переменную let posts = []. Именно в ней мы будем хранить все посты, которые у нас есть.

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

Он просто сгенерирует дубликат данного массива.


const BASE_URL = '/api/post'
let posts =[]
clss 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) куда и передадим эти посты.

Функцию опишем ниже. По умолчанию она будет принимать пустой массив - _posts=[]

У нас есть id="posts" в файле index.html куда нам нужно выводить наши посты.

$ - просто обозначает, что это некоторый элемент.


function renderPosts(_posts=[]) {
	const $posts = document.querySelector('#posts')

}



Далее, проверим. Если длина массива пришедшего в функция больше 0, то есть у нас есть некоторые посты, то мы будем генерировать карточки. Иначе мы просто выведем сообщение "Постов пока нет".

Если посты есть, то мы должны сгенерировать html. Нам нужно пробежаться по массиву постов и сформировать из каждого карточку с нужным html.

Мы можем обратиться к локальной переменной _posts и далее с помощью метода .map() мы на каждой итерации будем получать определенный post (это объект) и на выходе вернуть html, то есть вызвать функцию card(post)

Преобразуем массив к строке методом .join(' '). Через пробел.


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


Сохраняем и обновляем страницу Идем на вкладку Networkв в консоли.



Видим, что "Постов пока нет", а в запросах - url совпадает и метод GET, и получаем пустой массив post



С выводом постов мы разобрались.

Единственное что мы можем добавить, это индикатор загрузки.

Имитируем задержку сервера функцией setTimeout пред рендерингом постов, а на это время сделаем показ индикатора загрузки.


document.addEventListener('DOMContentLoaded', () => {
	PostApi.fetch().then(backendPosts => {
		posts = backendPosts.concat()
		setTimeout(()=>{
		renderPosts(posts)
		}, 2000)			
	})
})



Прелоудер возьмем на сайте materializecss.com

Скопируем там готовый код прелоудера и добавим его в наш див поста в файле index.html

Файл 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>


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



Файл 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 =[] class PostApi { static fetch(){ return fetch(BASE_URL, {method: 'get'}).then(res=>res.json()) } } document.addEventListener('DOMContentLoaded', () => { PostApi.fetch().then(backendPosts => { posts = backendPosts.concat() setTimeout(()=>{ renderPosts(posts) }, 2000) }) }) 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>` } }


Теперь перед загрузкой постов мы будем видеть индикатор - вращающиеся полуокружность и через 2 сек. сообщение "Постов пока нет".





                                                                                                                                                             

пятница, 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

среда, 7 марта 2018 г.

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

Плавная смена картинок при наведении курсора.

Весь код я рассказал здесь - Как изменить картинку при наведении на неё курсора, но получил несколько вопросов. Решил все собрать в одном месте. По шагам:
  1. Создаем новый пост и добавляем в него код HTML. Учтите, что image1.jpg - картинка, которая видна постоянно, а image2.jpg - та, которая будет появляться при наведении курсора
  2. <div class="animate2" style="margin-top: 100px;">
        <img class="first" height="" src="image2.jpg" width="100%" />
        <img class="second" height="" src="image1.jpg" width="100%" />
    </div>
    
  3. Теперь, где нибудь выше или ниже этого кода, прямо в вашем посте добавляем фото, которое будет видно постоянно - image1.jpg. Из всего добавленного кода, нас интересует только src нашей картинки. Копируем его и вставляем на место image1.jpg, внутри двойных кавычек
  4. Тоже самое проделываем во второй картинкой. После этого, код, который вы использовали для получения src картинок, можно полностью удалить.
  5. Идем в "Настройки" -> "Шаблоны+ ->"Продвинутые" ->"Добавить CSS" и вставляем код, котоый приведен ниже прям в поле отмеченное на втором фото






  6. .animate2{
    
      position:relative;
    
      margin:0 auto;/* устанваливаем блок div по центру страницы*/
    
      width:480px; /* Ширина */
    
      height: 360px;  /* Высота */                
    
    }
    
    .animate2 img {
    
      position:absolute; /* абсолютное позиционирование*/
    
      left: 0; /* выравниваем картинки по левому верхнему углу div-а*/
    
      top: 0; /* выравниваем картинки по левому верхнему углу div-а */  
    
    }
    .animate2 img.first { /* первая картинка полностью прозрачная */
    
      opacity:0;
    
      filter:alpha (opacity=0);
    
    }
    
    .animate2:hover img.first { /* при наведении курсора первая картинка становится не прозрачной */
    
      opacity:1;
    
      filter:alpha (opacity=100);
    
    }
    
    .animate2:hover img.second, .animate2 img.second:hover { /* а вторая при наведении курсора становится прозрачной */
    
      opacity:0;
    
      filter:alpha (opacity=0);
         -moz-transition: all 3s ease-in-out; /* эффект перехода для Firefox до версии 16.0 */
    
        -webkit-transition: all 3s ease-in-out; /* эффект перехода для Chrome до версии 26.0, Safari, Android и iOS */
    
        -o-transition: all 3s ease-in-out; /* эффект перехода для Opera до версии 12.10 */
    
        transition: all 3s ease-in-out; 
    }
    /*--для всех браузеров---*/
    .animate:not(:hover) img.second, .animate img.second:not(:hover) {
      
      
      -moz-transition: all 3s ease;
      -wedkit-transition: all 3s ease;
      -o-transition: all 3s ease;
      transition: all 3s ease;
    }
    /*---замедление возрата к началу--*/
    .animate2:not(:hover) img.first:not(:hover){
      opacity:0;
      filter: alpha (opacity=100);
       filter: alpha (opacity=0);
      -moz-transition: all 3s ease;
      -webkit-transition: all 3s ease;
      -o-transition: all 3s ease;
      transition: all 3s ease;
    }
    .animate2:not(:hover) img.second, .animate2 img.second:not(:hover) {
      opacity:1;
      filter: alpha (opacity=0);
      -moz-transition: all 3s ease;
      -webkit-transition: all 3s ease;
      -o-transition: all 3s ease;
      transition: all 3s ease;
    }
    


    Не забудьте сохранить изменения!





                                                                                                                                                             

воскресенье, 11 февраля 2018 г.

Как сделать копирование поля в браузер и очистка поля ввода.

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

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

Начнем с разметки html документа:

<body>
  <input id="in" type="text">
  <button type="button" onclick = "reset('in')" >Reset</button>
  <br /><br />
  <input id="out" class="js-copyinput" type="text" >
  <button type="button" onclick="getLink();">Get Link</button>
  <button class="js-inputcopybtn" >Copy Link</button>
</body>


Ничего нового. Обычные текстовые поля input с кнопками button и специфичными идентификаторами id, для привязки к нашему JS - коду.

Добавляем JS - код для копирования



<script>
 var copyTextareaBtn = document.querySelector('.js-inputcopybtn');

 copyTextareaBtn.addEventListener('click', function(event) {
  var copyTextarea = document.querySelector('.js-copyinput');
  copyTextarea.select();

  try {
   var successful = document.execCommand('copy');
   var msg = successful ? 'successful' : 'unsuccessful';
   alert('Copying text command was ' + msg);
  } catch (err) {
   alert('Oops, unable to copy');
  }
 });
</script>


Здесь, я думаю, что все понятно в коде и без пояснений. Берем поле с классом .js-copyinput и копируем его содержимое в браузер. Часть кода - try - catch добавлена для отображения процесса копирования пользователю. Я вывел уведомления в виде alert. Вы можете сделать это иначе или не показывать их вовсе. Но я думаю, что уведомления для пользователя нужны. Иначе не создается уверенности, что копирование информации в браузер прошло успешно.

JS - код для очистки полей.


Для того, чтобы нам очистить любое поле, нам достаточно просто написать в JS - коде, что значение этого поля равно пустой строке.
Например: document.getElementById('out').value = ""; Здесь мы говорим браузеру, что поле со значением out должно быть пустым.

<script>
function reset() { 
if (document.getElementById('in').value != "" || document.getElementById('out').value != "" )  {
document.getElementById('in').value = "";
document.getElementById('out').value = "";
}else {return false}; 
};
</script>
Посмотреть готовый пример можно на сайте Codepen

See the Pen Модератор Ссылки загрузкиГД с копированием и очисткой полей by YaroslavW (@YaroslavW) on CodePen.



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

                                                                                                                                                             

Как сделать ссылку для загрузки файлов с Гугл Диска.

Решил описать самый простой способ создания ссылки на загрузку файлов, папок, документов с Гугл-Диска сразу на компьютер пользователя.

Все началось с того, что я написал несколько полезных расширений для браузера Google Chrome и решил ими поделиться с друзьями, но не тут то было! Просто так сделать ссылку для скачивания со своего диска Google Drive не получилось. Дело в том, что Гугл Диск предоставляет по ссылке только просмотр файлов, мне же хотелось, чтобы при нажатии на ссылку "Скачать" - происходила загрузка файлов, а на ссылку "Просмотр" - можно было посмотреть файлы на диске до загрузки.

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

Добавление атрибута download непосредственно к ссылке не принесло ожидаемого результата. Файлы загружались, но не в zip-архиве, или в существующем формате, а только как некое подобие html-документа.

Вот пример - создал папку на Диске, прошел -> "Включить доступ по ссылке" -> "Получить ссылку".

Для пробы я использовал Codepen. Здесь вы можете посмотреть, что получилось.

See the Pen загрузка папки by YaroslavW (@YaroslavW) on CodePen.



Если коротко, то создал обычную ссылку в которую добавил атрибут download. Путь к файлу - href указал, тот, что получил с диска.

При попытке скачать, произошло то, о чем я говорил выше. Предлагается сохранить файл в формате .htm

См. фото ниже.



Помог поиск в Гугл. Оказывается. что все дело в ссылке. Предложенная ссылка была такая:
https://drive.google.com/open?id=103vuGWLfwofXNR4pdFm986lBhETCbjQL
А для ссылки загрузки требовалась вот такая:
https://drive.google.com/uc?export=download&confirm=no_antivirus&id=103vuGWLfwofXNR4pdFm986lBhETCbjQL

В принципе, на этом можно бы было и закончить этот пост. Потому что все что вам потребуется, это:
  1. Получить ссылку на вашу папку (или документ) на Google Drive
  2. Взять от нее (скопировать) идентификатор -id=///
  3. Подставить в ссылку для загрузки (выделено красным)
Мне простые пути очень нравятся, но что делать, если ссылок много, или человек ну очень хочет разбираться во всем этом, ну и просто захотелось облегчить кому-то труд?

Решил написать простой скрипт, который бы производил все автоматически. И пошло и поехало. Потому что захотелось, чтобы стояла кнопка - "Copy", при нажатии на которую сразу бы копировался код ссылки в браузер. Потом решил, что нужно поставить кнопку очистки поля ввода - Reset, которая бы облегчала задачу многократного ввода.

Все это я описал в посте.

Ниже предлагаю воспользоваться модификатором ссылок для загрузки файлов с диска.





Код для модификации ссылки я применял очень простой:

function getLink(){
  var custom = document.getElementById('in').value;
  var output = document.getElementById('out');
  
  var fl = custom.indexOf("id=");
  console.log(fl);
  var custPart = custom.substring(fl+3);
console.log(custPart);
  var answer = "https://drive.google.com/uc?export=download&confirm=no_antivirus&id=" + custPart;
  output.value = answer;
};


Понятное дело, что к этому коду требуется соответствующая html разметка.

Подробнее об этом в посте Как сделать копирование поля в браузер и очистка поля ввода.

Удачи вам, друзья и пользуйтесь "Простыми советами" для того, чтобы сделать свою жизнь немного проще, легче и приятнее!

                                                                                                                                                             


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