c-searchbar
, c-searchbar-menu
, c-searchbar-dropdown
, c-searchbar-megamenu
, c-searchbar-megamenu-tags
(бем с префиксами)<div class="c-searchbar">
...
<ul class="c-searchbar__menu c-searchbar-menu">
<li class="dropdown [ c-searchbar__dropdown c-searchbar-dropdown ]">
<a href="#" class="dropdown-toggle [ c-searchbar-menu__link ]" data-toggle="dropdown">Country <b class="caret"></b></a>
<div class="dropdown-menu [ c-searchbar__megamenu c-searchbar-megamenu ]">
<div class="container">
<div class="c-searchbar-megamenu__header">
<div class="c-searchbar-megamenu__tags c-searchbar-megamenu-tags">
<div class="c-searchbar-megamenu-tags__item">CZECH REPUBLIC <button type="button" class="remove-tag"></button></div>
<div class="c-searchbar-megamenu-tag__item">CONSUMERS ELECTRONICS</div>
</div>
</div>
</div>
</div>
</li>
<li class="c-searchbar-menu__item"></li>
</ul>
...
</div>
c-searchbar-dropdown
, а должен для этих целей использовать c-searchbar__dropdown
. Если же компонент c-searchbar-dropdown
не будет иметь правил позиционирования ,то можно(наверное) убрать класс c-searchbar__dropdown
data-react-checksum
клиетского приложения и серверного. Если совпадают, это означает, что если мы "поднимем" клиентское приложение(дорогая операция), то что мы получим будет совпадать с тем, что отправил сервер. Выходит, что этого можно избежать. Именно это и делает реакт, просто копирует полученный на сервер DOM в клиентское приложение.let array = Array.from({ length: 10 }, (v, k) => k);
const fn = (el) => {
setTimeout(() => { console.log(el) }, 100 * el);
return el * 2;
};
console.log(array.map(fn));
d
- это NodeList (список узлов), не имеющий метода hasAttribute()
var tags = ['div', 'span', 'ul', 'li', 'p', 'script', 'h1', 'h2'];
var forEach = Array.prototype.forEach
tags.map(function(tag) {
var list = document.querySelectorAll(tag);
forEach.call(list, function(el) {
el.className && console.log(el.className)
})
})
display: none
, затем когда при прокрутке добавляешь класс .top-nav-collapse
элементу nav
возвращаешь гамбургер через display: block
nav navbar-nav navbar-right navbar-border
добавляешь айдишку mobileNav
var mobileNav = document.getElementById('mobileNav')
var navbarToggler = document.querySelector('.navbar-toggle')
mobileNav.addEventListener('click', onMobileNavLink)
function onMobileNavClick(e) {
if (e.target && e.target.nodeName === 'A') { // если нажал на ссылку в пределах меню
navbarToggler.click() // закрываешь меню
}
npm install -g yo
npm install -g webapp-generator
npm install -g gulp-cli bower
yo webapp
чтобы поднять каркасvar items = Array.prototype.slice.call( document.querySelectorAll('div') )
var products = [
{name:"Grapefruit", calories: 170, color: "red", sold: 8200},
{name:"Orange", calories: 160, color: "orange", sold: 12101},
{name:"Cola", calories: 210, color: "caramel", sold: 25412},
{name:"Diet cola", calories: 0, color: "caramel", sold: 43922},
{name:"Lemon", calories: 200, color: "clear", sold: 14983},
{name:"Rapsberry", calories: 180, color: "pink", sold: 9427},
{name:"Root Beer", calories: 200, color: "caramel", sold: 9909},
{name:"Water", calories: 0, color: "clear", sold: 62123}
];
var mapper = {
'sold': function (product) {
console.log('Продукт: ' + product.name + ' был продан ' + product.sold + ' раз.');
},
'name': function (product) {
console.log('Название продукта: ' + product.name);
},
'calories': function (product) {
console.log('Продукт: ' + product.name + ' имеет ' + product.calories + ' калорий.');
},
'color': function (product) {
console.log('Продукт: ' + product.name + ' имеет ' + product.color + ' цвет.');
}
};
printBy(products, 'calories');
function printBy(collection, prop) {
collection.map(mapper[prop]);
}
case 'SWITCH_EDIT_MODE':
return Object.assign({}, state, {
editMode: action.value
})
case 'SWITCH_EDIT_MODE':
return { ...state, editMode: action.value}
weatherApiId
спрятать в .env
, а .env
кинуть в .gitignore
(dotenv-webpack to the rescue)MainContainer
на мой взглядimport React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionCreators from './../../actions/actionCreators';
import Main from './../Main/Main';
class MainContainer extends React.Component {
componentDidMount() {
this.props.actions.detectLocation();
}
render() {
return <Main {...this.props.store} {...this.props.actions} />
}
}
const mapStateToProps = state => ({ store: state })
const mapDispatchToProps = dispatch => ({ actions: bindActionCreators(actionCreators, dispatch) })
export default connect(mapStateToProps, mapDispatchToProps)(MainContainer)
Main
соответсвенно import React from 'react';
import PropTypes from 'prop-types';
import styles from './Main.css';
import PageBackground from './../PageBackground/PageBackground';
import WeatherIcon from './../WeatherIcon/WeatherIcon';
import Temperature from './../Temperature/Temperature';
import Location from './../Location/Location';
import Loader from './../Loader/Loader';
import Error from './../Error/Error';
const propTypes = {
pageBackground: PropTypes.string,
location: PropTypes.object,
editMode: PropTypes.bool,
changeLocation: PropTypes.func,
switchEditMode: PropTypes.func,
weatherIcon: PropTypes.string,
temperature: PropTypes.number,
weatherDescription: PropTypes.string
};
export default function Main (props) {
return (
<div className={styles.container}>
{props.loading && <Loader />}
{props.loadingError && <Error>Sorry, an error occurred. Try to reload page</Error>}
<PageBackground background={props.pageBackground} />
<Location city={props.location.city}
editMode={props.editMode}
onLocationSelect={props.changeLocation}
onChangeLocationClick={() => props.switchEditMode(true)}
onInputBlur={() => props.switchEditMode(false)} />
<div className={styles.split}>
<WeatherIcon code={props.weatherIcon} class={styles.icon}/>
<span className={styles.date}>Today</span>
</div>
<Temperature value={props.temperature}/>
<div className={styles.description}>props.weatherDescription}</div>
</div>
)
}
Main.propTypes = propTypes;
MainContainer
должны (в этом проекте) быть functional components. MainContainer
, чтобы представить в функуиональном видеconst timer = document.getElementById("my_timer");
// выбери "время в секундах" или число вызовов функции startTimer()
let total = 60;
// сохраним в переменную, чтобы потом очистить
let timerInterval = setInterval(tick, 1000);
// достаём число, минуты, секунды в числовом формате
const getHours = x => Math.floor( total / 3600 )
const getMinutes = x => Math.floor( total % 3600 / 60)
const getSeconds = x => Math.floor( total % 3600 % 60 )
// приводим вышеуказанные значения в нужный для отображения вид
const prepair = val => val < 10 ? '0' + val : val
// эта функция принимает фукцию и вызывает её, передав в качестве аргумента total
const passTotal = fn => fn(total);
function tick() {
// типа делаем [a, b] = [10, 20] и получаем a = 10 и b = 20 (деструктивное присваивание)
const [hour, minutes, seconds] = [getHours, getMinutes, getSeconds].map(passTotal)
if (total <= 0) {
clearInterval(timerInterval)
// return fetchAnotherQuestion()
}
// отображаем строку
timer.textContent = prepair(hour)+ ':' + prepair(minutes) + ':' + prepair(seconds)
// уменьшаем "время в секундах" на "одну секунду"
total--;
}