Logomotion: Introduction Javascript
This commit is contained in:
parent
050515bbe6
commit
d3914eb51e
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -0,0 +1,628 @@
|
|||
<style>
|
||||
pre { font-size: 0.5em !important; }
|
||||
table { font-size: 0.6em !important; }
|
||||
</style>
|
||||
|
||||
# Présentation de framework Javascript
|
||||
## William Petit - S.C.O.P. Cadoles
|
||||
|
||||
---
|
||||
|
||||
## Riot
|
||||
## React + Flux
|
||||
## Ember
|
||||
|
||||
---
|
||||
|
||||
## Riot
|
||||
|
||||
### Présentation générale
|
||||
### Concepts généraux
|
||||
### Exercice
|
||||
|
||||
---
|
||||
|
||||
## Présentation générale (1)
|
||||
|
||||
- Publication: Septembre 2013
|
||||
- Mainteneurs principaux: [@GianlucaGuarini](https://github.com/GianlucaGuarini) et [@tipiirai](https://github.com/tipiirai) (projet communautaire)
|
||||
- License: MIT
|
||||
|
||||
---
|
||||
|
||||
## Présentation générale (2)
|
||||
|
||||
|Avantages|Inconvénients|
|
||||
|:-|:-|
|
||||
|Une librairie et pas un framework| Une librairie et pas un framework|
|
||||
| Projet communautaire | Projet communautaire |
|
||||
| Orientée "composant" | |
|
||||
| API minimaliste |
|
||||
| Prêt à l'emploi (pas de transpilage nécessaire en développement) |
|
||||
| Routeur "frontend" disponible |
|
||||
|
||||
---
|
||||
|
||||
## Concepts généraux
|
||||
|
||||
### Composants ("tags")
|
||||
### Observable
|
||||
|
||||
---
|
||||
|
||||
## Composants
|
||||
|
||||
### Structure et utilisation d'un composant
|
||||
### Templating
|
||||
### Styles de composant
|
||||
### Évènements du DOM
|
||||
### Cycle de vie du composant
|
||||
|
||||
---
|
||||
|
||||
## Structure d'un composant
|
||||
|
||||
```html
|
||||
<!-- components/my-tag.tag -->
|
||||
|
||||
<!-- Racine du Tag -->
|
||||
<my-tag>
|
||||
|
||||
<!-- Définition du DOM -->
|
||||
<span>{ opts.foo }</span>
|
||||
|
||||
<!-- Style du composant -->
|
||||
<style>
|
||||
:scope {
|
||||
display: block
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Script du composant -->
|
||||
<script>
|
||||
this.on('mount', () => {
|
||||
this.opts.foo = "bar";
|
||||
});
|
||||
</script>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Utilisation du composant
|
||||
|
||||
### Compilation dans le navigateur
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<!-- Utilisation du composant dans notre page HTML -->
|
||||
<my-tag></my-tag>
|
||||
|
||||
<!-- Inclusion de notre "tag" -->
|
||||
<script type="riot/tag" src="components/my-tag.tag"></script>
|
||||
|
||||
<!-- Inclusion de la librairie Riot + compilateur -->
|
||||
<script type="text/javascript" src="js/riot+compiler.js"></script>
|
||||
|
||||
<!-- Montage des composants Riot -->
|
||||
<script type="text/javascript">
|
||||
var opts = {}; // Options passées à tous les tags
|
||||
riot.mount('*', opts)
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Templating
|
||||
|
||||
```html
|
||||
<my-tag>
|
||||
|
||||
<!-- Interpolation simple -->
|
||||
<span>{ foo }</span> <!-- <span>bar</span> -->
|
||||
|
||||
<!-- Boucles -->
|
||||
<ul>
|
||||
<li each={ item in myItems }>{ item.text }</li>
|
||||
</ul>
|
||||
|
||||
<!-- Condition avec appel de méthode -->
|
||||
|
||||
<span if={ isFooBar() }>foo est égal à "bar" !</span>
|
||||
|
||||
<script>
|
||||
|
||||
this.foo = "bar"
|
||||
|
||||
this.myItems = [
|
||||
{ text: "Hello World" },
|
||||
{ text: "Foo Bar" }
|
||||
];
|
||||
|
||||
isFooBar() {
|
||||
return this.foo == "bar";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Styles de composant
|
||||
|
||||
### Feuille de style
|
||||
### Styles et classes dynamiques
|
||||
|
||||
---
|
||||
|
||||
## Feuille de style
|
||||
|
||||
```html
|
||||
<my-tag>
|
||||
|
||||
<!-- Définition du DOM -->
|
||||
<span id="foo">Foo</span>
|
||||
<div class="bar">Bar</div>
|
||||
|
||||
<!-- Style du composant -->
|
||||
<style>
|
||||
:scope {
|
||||
display: block
|
||||
}
|
||||
#foo {
|
||||
color: red;
|
||||
}
|
||||
.bar {
|
||||
background: blue;
|
||||
}
|
||||
</style>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Styles et classes dynamiques
|
||||
|
||||
```html
|
||||
<my-tag>
|
||||
|
||||
<!-- Définition du DOM -->
|
||||
<span style={ fooStyles }>Foo</span>
|
||||
<div class={ barClasses }>Bar</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
this.fooStyles = {
|
||||
color: "red"
|
||||
}
|
||||
|
||||
this.barClasses = {
|
||||
"bar": true, // Classes conditionnelles
|
||||
"foo": false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Évènements du DOM
|
||||
|
||||
|
||||
```html
|
||||
<my-tag>
|
||||
|
||||
<button onclick={ onButtonClick }>Click me !</button>
|
||||
|
||||
<script>
|
||||
|
||||
onButtonClick(evt) {
|
||||
|
||||
// Si l'élément à l'origine se trouve dans une boucle each={ ...},
|
||||
// evt.item pointera vers l'élément courant
|
||||
|
||||
console.log(evt);
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cycle de vie du composant
|
||||
|
||||
```html
|
||||
<my-tag>
|
||||
|
||||
<script>
|
||||
this.on('before-mount', () => console.log('before-mount'));
|
||||
this.on('mount', () => console.log('mount'));
|
||||
this.on('update', () => console.log('update'));
|
||||
this.on('updated', () => console.log('updated'));
|
||||
this.on('before-unmount', () => console.log('before-unmount'));
|
||||
this.on('unmount', () => console.log('unmount'));
|
||||
</script>
|
||||
|
||||
</my-tag>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Observable (1)
|
||||
|
||||
### Déclaration d'un "service"
|
||||
```javascript
|
||||
// services/auth.js
|
||||
class MyAuthService {
|
||||
|
||||
constructor() {
|
||||
riot.observable(this)
|
||||
this.user = null;
|
||||
}
|
||||
|
||||
login(user, password) {
|
||||
|
||||
var form = new FormData();
|
||||
form.append('login', login);
|
||||
form.append('password', password);
|
||||
|
||||
return fetch('/login', { method: 'POST', form: form })
|
||||
.then(res => res.json())
|
||||
.then(user => {
|
||||
this.user = user;
|
||||
this.trigger('loggedIn', user);
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
isLoggedIn() {
|
||||
return this.user != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const myAuth = new MyAuthService();
|
||||
```
|
||||
|
||||
---
|
||||
## Observable (2)
|
||||
|
||||
### Utilisation du service
|
||||
|
||||
```html
|
||||
<my-app></my-app>
|
||||
|
||||
<!-- Tag "inline" -->
|
||||
<script type="riot/tag">
|
||||
|
||||
<my-app>
|
||||
<button if={ !user }
|
||||
onclick={ login }>
|
||||
Login
|
||||
</button>
|
||||
<span if={ user }>User: { user.name }</span>
|
||||
</my-app>
|
||||
|
||||
<script>
|
||||
this.user = null;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.opts.auth.on('loggedIn', user => {
|
||||
this.user = user;
|
||||
this.update();
|
||||
});
|
||||
});
|
||||
|
||||
login() {
|
||||
this.opts.auth.login();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="services/auth.js"></script>
|
||||
<script type="text/javascript">riot.mount('*', { auth: myAuth })</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercice
|
||||
|
||||
Implémenter une application minimaliste de gestion de tâches avec Riot. Cette application doit comprendre les fonctionnalités suivantes:
|
||||
|
||||
- Ajouter une nouvelle tâche (champs texte) avec une priorité parmi les suivantes: "haute", "moyenne", "basse" et un statut: "en cours" ou "terminé"
|
||||
- Marquer une tâche comme "terminée".
|
||||
- Afficher la liste des tâches en attente, triées par priorité décroissante + tâches terminées en dernier.
|
||||
- Les tâches doivent être persistées dans le "Local Storage" du navigateur.
|
||||
|
||||
---
|
||||
|
||||
## React + Flux
|
||||
|
||||
### Présentation générale
|
||||
### Concepts généraux
|
||||
### Prise en main
|
||||
|
||||
---
|
||||
|
||||
## Présentation générale (1)
|
||||
|
||||
|
||||
- Publication: Mars 2013
|
||||
- Mainteneur principal: Facebook
|
||||
- License: MIT
|
||||
|
||||
---
|
||||
|
||||
## Présentation générale (2)
|
||||
|
||||
|
||||
|Avantages|Inconvénients|
|
||||
|:-|:-|
|
||||
|Grande communauté, très active | Changement de license puis rétropédalage en 2017 |
|
||||
| Maintenu et utilisé par Facebook en interne | Nécessité de mettre en place un pipeline de transpilage |
|
||||
| Architecture Flux | Architecture Flux |
|
||||
| Possibilité de faire des applications "isomorphiques" avec NodeJS |
|
||||
| "React Native" |
|
||||
| API stable |
|
||||
| Virtual DOM |
|
||||
| Moteurs "lightweight" compatibles |
|
||||
|
||||
---
|
||||
|
||||
## Concepts généraux
|
||||
|
||||
### Composants
|
||||
### L'architecture Flux
|
||||
|
||||
---
|
||||
|
||||
## Composants
|
||||
|
||||
### Structure d'un composant
|
||||
### Props
|
||||
### State
|
||||
### Évènements du DOM
|
||||
### Cycle de vie d'un composant
|
||||
|
||||
---
|
||||
|
||||
## Structure d'un composant
|
||||
|
||||
```jsx
|
||||
// components/hello-world.js
|
||||
|
||||
import React from 'react'
|
||||
|
||||
class HelloWorld extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='hello-world'>
|
||||
<h1>Hello World</h1>
|
||||
<p>Welcome to React</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default HelloWorld
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Props
|
||||
|
||||
```jsx
|
||||
// components/props-example.js
|
||||
|
||||
import React from 'react'
|
||||
|
||||
class PropsExample extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<span>{ this.props.text }</span>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PropsExample
|
||||
|
||||
// app.js
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import PropsExample from './components/props-example'
|
||||
|
||||
const mountpoint = document.getElementById('props-example');
|
||||
|
||||
ReactDOM.render(<PropsExample text="foo bar" />, mountpoint)
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State
|
||||
|
||||
```jsx
|
||||
// components/clock.js
|
||||
|
||||
import React from 'react'
|
||||
|
||||
class Clock extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
// On fait appel au constructeur de la classe
|
||||
// parente
|
||||
super(props)
|
||||
|
||||
// Initialisation du "state" du composant
|
||||
this.state = {
|
||||
time: new Date()
|
||||
}
|
||||
// On appelle la méthode tick() du composant
|
||||
// toutes les secondes
|
||||
setInterval(this.tick.bind(this), 1000);
|
||||
}
|
||||
|
||||
// Méthode de rendu du composant
|
||||
render() {
|
||||
return (
|
||||
<div>Time: { this.state.time.toString() }</div>
|
||||
)
|
||||
}
|
||||
|
||||
// La méthode tick() met à jour le state du composant avec
|
||||
// la date courante
|
||||
tick() {
|
||||
this.setState({ time: new Date() });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default Clock
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Évènements du DOM
|
||||
|
||||
```jsx
|
||||
// components/counter.js
|
||||
import React from 'react'
|
||||
|
||||
class Counter extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
// On fait appel au constructeur de la classe
|
||||
// parente
|
||||
super(props)
|
||||
|
||||
// Initialisation du "state" du composant
|
||||
this.state = {
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode de rendu du composant
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
Count: <span>{ this.state.count }</span>
|
||||
<button onClick={ () => this.increment() }>+1</button>
|
||||
<button onClick={ () => this.decrement() }>-1</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// La méthode increment() incrémente la valeur du compteur de 1
|
||||
increment() {
|
||||
this.setState(prevState => ({ count: prevState.count+1 }))
|
||||
}
|
||||
|
||||
// La méthode decrement() incrémente la valeur du compteur de 1
|
||||
decrement() {
|
||||
this.setState(prevState => ({ count: prevState.count-1 }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Counter
|
||||
```
|
||||
---
|
||||
|
||||
## Cycle de vie d'un composant
|
||||
|
||||
```
|
||||
// components/clock-lifecycle.js
|
||||
import React from 'react'
|
||||
|
||||
class Clock extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
time: new Date()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
console.log('mount')
|
||||
this.intervalId = setInterval(this.tick.bind(this), 1000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
console.log('unmount')
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>Time: { this.state.time.toString() }</div>
|
||||
)
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.setState({ time: new Date() });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Clock
|
||||
```
|
||||
---
|
||||
|
||||
## L'architecture Flux
|
||||
|
||||
![center](./img/flux-simple-f8-diagram-with-client-action-1300w.png)
|
||||
|
||||
---
|
||||
|
||||
## Exercice
|
||||
|
||||
Implémenter une application minimaliste de gestion de tâches avec React (sans l'architecture Flux). Cette application doit comprendre les fonctionnalités suivantes:
|
||||
|
||||
- Ajouter une nouvelle tâche (champs texte) avec une priorité parmi les suivantes: "haute", "moyenne", "basse" et un statut: "en cours" ou "terminé"
|
||||
- Marquer une tâche comme "terminée".
|
||||
- Afficher la liste des tâches en attente, triées par priorité décroissante + tâches terminées en dernier.
|
||||
- Les tâches doivent être persistées dans le "Local Storage" du navigateur.
|
||||
|
||||
---
|
||||
|
||||
## Ember
|
||||
|
||||
### Présentation générale
|
||||
### Concepts généraux
|
||||
### Initialisation d'un projet
|
||||
### Exercice
|
||||
|
||||
---
|
||||
|
||||
|
||||
# Licence
|
||||
|
||||
## CC BY-NC-SA 3.0 FR
|
||||
|
||||
[Creative Commons - Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 France](https://creativecommons.org/licenses/by-nc-sa/3.0/fr/)
|
Loading…
Reference in New Issue