diff --git a/src/images/devtools-storage-chrome.png b/src/images/devtools-storage-chrome.png new file mode 100644 index 0000000000..9271dd57e5 Binary files /dev/null and b/src/images/devtools-storage-chrome.png differ diff --git a/src/images/devtools-storage-edge.png b/src/images/devtools-storage-edge.png new file mode 100644 index 0000000000..d05024b643 Binary files /dev/null and b/src/images/devtools-storage-edge.png differ diff --git a/src/images/devtools-storage.png b/src/images/devtools-storage.png new file mode 100644 index 0000000000..44e2998185 Binary files /dev/null and b/src/images/devtools-storage.png differ diff --git a/src/v2/api/index.md b/src/v2/api/index.md index 21b337ea90..f855cdbe40 100644 --- a/src/v2/api/index.md +++ b/src/v2/api/index.md @@ -1590,14 +1590,139 @@ type: api - Si l'évènement et la fonction de rappel sont fournis, supprime l'écouteur uniquement pour cet événément et cette fonction de rappel spécifique. -### vm.$emit( event, [...args] ) +### vm.$emit( eventName, [...args] ) - **Arguments :** - - `{string} évènement` + - `{string} nom d'évènement` - `[...arguments]` Déclenche un évènement sur l'instance actuelle. Tous les arguments additionnels sont passés à la fonction de rappel de l'écouteur. +- **Exemples:** + + Utiliser `$emit` avec un nom d'évènement : + + ```js + Vue.component('welcome-button', { + template: ` + + ` + }) + ``` + ```html +
+ +
+ ``` + ```js + new Vue({ + el: '#emit-example-simple', + methods: { + sayHi: function () { + alert('Salut !') + } + } + }) + ``` + {% raw %} +
+ +
+ + {% endraw %} + + Utiliser `$emit` avec des arguments additionnels : + + ```js + Vue.component('magic-eight-ball', { + data: function () { + return { + possibleAdvice: ['Oui', 'Non', 'Peut-être'] + } + }, + methods: { + giveAdvice: function () { + var randomAdviceIndex = Math.floor(Math.random() * this.possibleAdvice.length) + this.$emit('give-advice', this.possibleAdvice[randomAdviceIndex]) + } + }, + template: ` + + ` + }) + ``` + + ```html +
+ +
+ ``` + + ```js + new Vue({ + el: '#emit-example-argument', + methods: { + showAdvice: function (advice) { + alert(advice) + } + } + }) + ``` + + {% raw %} +
+ +
+ + {% endraw %} + ## Méthodes d'Instance / Cycle de Vie ### vm.$mount( [élémentOuSelecteur] ) diff --git a/src/v2/cookbook/avoiding-memory-leaks.md b/src/v2/cookbook/avoiding-memory-leaks.md index 34d341518f..cd4fc7a061 100644 --- a/src/v2/cookbook/avoiding-memory-leaks.md +++ b/src/v2/cookbook/avoiding-memory-leaks.md @@ -5,7 +5,7 @@ order: 10 --- ## Introduction -If you are developing applications with Vue, then you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs) because by design, users should not have to refresh their browser when using an SPA, so it is up to the Javascript application to clean up components and make sure that garbage collection takes place as expected. +

Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.

If you are developing applications with Vue, then you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs) because by design, users should not have to refresh their browser when using an SPA, so it is up to the JavaScript application to clean up components and make sure that garbage collection takes place as expected.

Memory leaks in Vue applications do not typically come from Vue itself, rather they can happen when incorporating other libraries into an application. @@ -166,4 +166,4 @@ deactivated: function () { ## Wrapping Up -Vue makes it very easy to develop amazing, reactive Javascript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary. \ No newline at end of file +Vue makes it very easy to develop amazing, reactive JavaScript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary. \ No newline at end of file diff --git a/src/v2/cookbook/client-side-storage.md b/src/v2/cookbook/client-side-storage.md new file mode 100644 index 0000000000..646edd808f --- /dev/null +++ b/src/v2/cookbook/client-side-storage.md @@ -0,0 +1,176 @@ +--- +title: Client-Side Storage (EN) +type: cookbook +order: 11 +--- + +## Base Example + +

Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.

Client-side storage is an excellent way to quickly add performance gains to an application. By storing data on the browser itself, you can skip fetching information from the server every time the user needs it. While especially useful when offline, even online users will benefit from using data locally versus a remote server. Client-side storage can be done with [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) (technically "Web Storage"), [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API), and [WebSQL](https://www.w3.org/TR/webdatabase/) (a deprecated method that should not be used in new projects).

+ +In this cookbook entry we'll focus on Local Storage, the simplest of the storage mechanisms. Local Storage uses a key/value system for storing data. It is limited to storing only simple values but complex data can be stored if you are willing to encode and decode the values with JSON. In general, Local Storage is appropriate for smaller sets of data you would want to persist, things like user preferences or form data. Larger data with more complex storage needs would be better stored typically in IndexedDB. + +Let's begin with a simple form based example: + +``` html +
+ My name is +
+``` + +This example has one form field bound to a Vue value called `name`. Here's the JavaScript: + +``` js +const app = new Vue({ + el:'#app', + data: { + name:'' + }, + mounted() { + if(localStorage.name) this.name = localStorage.name; + }, + watch: { + name(newName) { + localStorage.name = newName; + } + } +}); +``` + +Focus on the `mounted` and `watch` parts. We use `mounted` to handle loading the value from localStorage. To handle writing the data base, we watch the `name` value and on change, immediately write it. + +You can run this yourself here: + +

See the Pen testing localstorage by Raymond Camden (@cfjedimaster) on CodePen.

+ + +Type something in the form and then reload this page. You'll note that the value you typed previously will show up automatically. Don't forget that your browser provides excellent developer tools for inspecting client-side storage. Here's an example in Firefox: + +![Storage devtools in Firefox](/images/devtools-storage.png) + +And here it is in Chrome: + +![Storage devtools in Chrome](/images/devtools-storage-chrome.png) + +And then finally, an example in Microsoft Edge. Note that you can find application storage values under the Debugger tab. + +![Storage devtools in Edge](/images/devtools-storage-edge.png) + +

As a quick aside, these dev tools also offer you a way to remove storage values. This can be very useful when testing.

+ +Immediately writing the value may not advisable. Let's consider a slightly more advanced example. First, the updated form. + +``` html +
+ My name is + and I am years old. +

+ +

+``` + +Now we've got two fields (again, bound to a Vue instance) but now there is the addition of a button that runs a `persist` method. Let's look at the JavaScript. + +``` js +const app = new Vue({ + el:'#app', + data: { + name:'', + age:0 + }, + mounted() { + if(localStorage.name) this.name = localStorage.name; + if(localStorage.age) this.age = localStorage.age; + }, + methods: { + persist() { + localStorage.name = this.name; + localStorage.age = this.age; + console.log('now pretend I did more stuff...'); + } + } +}) +``` + +As before, `mounted` is used to load persisted data, if it exists. This time, though, data is only persisted when the button is clicked. We could also do any validations or transformations here before storing the value. You could also store a date representing when the values were stored. With that metadata, the `mounted` method could make a logical call on whether or not to store the values again, such as in this version below. You can try this version below. + +

See the Pen testing localstorage 2 by Raymond Camden (@cfjedimaster) on CodePen.

+ + +## Working with Complex Values + +As mentioned above, Local Storage only works with simple values. To store more complex values, like objects or arrays, you must serialize and deserialize the values with JSON. Here is a more advanced example that persists an array of cats (the best kind of array possible). + +``` html +
+

Cats

+
+

+ {{cat}} +

+
+ +

+ + +

+ +
+``` + +This "app" consists of a simple list on top (with a button to remove a cat) and a small form at the bottom to add a new cat. Now let's look at the JavaScript. + +``` js +const app = new Vue({ + el:'#app', + data: { + cats:[], + newCat:null + }, + mounted() { + + if(localStorage.getItem('cats')) { + try { + this.cats = JSON.parse(localStorage.getItem('cats')); + } catch(e) { + localStorage.removeItem('cats'); + } + } + }, + methods: { + addCat() { + // ensure they actually typed something + if(!this.newCat) return; + this.cats.push(this.newCat); + this.newCat = ''; + this.saveCats(); + }, + removeCat(x) { + this.cats.splice(x,1); + this.saveCats(); + }, + saveCats() { + let parsed = JSON.stringify(this.cats); + localStorage.setItem('cats', parsed); + } + } +}) +``` + +In this application, we've switched to use the Local Storage APIs versus "direct" access. Both work but the API method is generally preferred. `mounted` now has to grab the value and parse the JSON value. If anything goes wrong here we assume the data is corrupt and delete it. (Remember, any time your web application uses client-side storage, the user has access to it and can modify it at will.) + +We have three methods now to handle working with cat. Both `addCat` and `removeCat` handle updating the "live" Vue data stored in `this.cats`. They then run `saveCats` which handles serializing and persisting the data. You can play with this version below: + +

See the Pen localstorage, complex by Raymond Camden (@cfjedimaster) on CodePen.

+ + +## Alternative Patterns + +While the Local Storage API is relatively simple, it is missing some basic features that would be useful in many applications. The following plugins wrap Local Storage access and make it easier to use, while also adding functionality like default values. + +* [vue-local-storage](https://github.com/pinguinjkeke/vue-local-storage) +* [vue-reactive-storage](https://github.com/ropbla9/vue-reactive-storage) + +## Wrapping Up + +While the browser will never replace a server persistence system, having multiple ways to cache data locally can be a huge performance boost for your application, and working with it in Vue.js makes it even more powerful. diff --git a/src/v2/cookbook/creating-custom-scroll-directives.md b/src/v2/cookbook/creating-custom-scroll-directives.md index fb9eb351b9..99ca0c7a49 100644 --- a/src/v2/cookbook/creating-custom-scroll-directives.md +++ b/src/v2/cookbook/creating-custom-scroll-directives.md @@ -50,7 +50,7 @@ new Vue({ We'd also need a style property that will transition the intermediary values here, in this case: -``` +```css .box { transition: 1.5s all cubic-bezier(0.39, 0.575, 0.565, 1); } diff --git a/src/v2/cookbook/packaging-sfc-for-npm.md b/src/v2/cookbook/packaging-sfc-for-npm.md new file mode 100644 index 0000000000..418aa2e864 --- /dev/null +++ b/src/v2/cookbook/packaging-sfc-for-npm.md @@ -0,0 +1,216 @@ +--- +title: Packaging Vue Components for npm (EN) +type: cookbook +order: 12 +--- + +## Base Example + +

Cette page est en cours de traduction. Pour nous aider, vous pouvez participer sur le dépôt GitHub dédié de Vuejs-FR.

Vue components by nature are meant to be re-used. This is easy when the component is only used within a single application. But how can you write a component once and use it in multiple sites/applications? Perhaps the easiest solution is via npm.

+ +By packaging your component to be shared via npm, it can be imported/required into a build process for use in full-fledged web applications: + +```js +import MyComponent from 'my-component'; + +export default { + components: { + MyComponent, + }, + // rest of the component +} +``` + +Or even used via ` + + ... + + ... +``` + +Not only does this help you avoid copy/pasting components around, but it also allows you to give back to the Vue community! + +## Can't I Just Share `.vue` Files Directly? + +Vue already allows components to be written as a single file. Because a Single File Component (SFC) is already just one file, you might ask: + +> "Why can't people use my `.vue` file directly? Isn't that the simplest way to share components?" + +It's true, you can share `.vue` files directly, and anyone using a [Vue build](https://vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds) containing the Vue compiler can consume it immediately. Also, the SSR build uses string concatenation as an optimization, so the `.vue` file might be preferred in this scenario (see [Packaging Components for npm > SSR Usage](#SSR-Usage) for details). However, this excludes anyone who wishes to use the component directly in a browser via ` @@ -130,6 +130,10 @@ Une autre option que les développeurs Vue auront bientôt est l'utilisation de MobX est devenu populaire dans la communauté React et utilise actuellement un système de réactivité identique à Vue. Dans une certaine mesure, le workflow React + MobX peut être considéré comme plus verbeux que Vue. Donc si vous utilisez cette combinaison et qu'elle vous plait, passer sur Vue est probablement la prochaine étape logique. +### Preact et les autres bibliothèques de type React + +Les bibliothèques de type React essayent généralement de partager le plus possible leur API et leur écosystème avec React. Pour cette raison, la grande majorité des comparaisons ci-dessus leur seront également applicables. La principale différence sera généralement un écosystème réduit, souvent de manière significative, par rapport à React. Étant donné que ces bibliothèques ne peuvent pas être 100% compatibles dans l'écosystème React, certaines bibliothèques d'outils et de compagnons ne peuvent pas être utilisables. Ou, même s'ils semblent fonctionner, ils peuvent se bloquer à tout moment à moins que votre bibliothèque spécifique de type React ne soit officiellement supportée par React. + ## AngularJS (Angular 1) Une partie de la syntaxe de Vue ressemblera très fortement à celle de AngularJS (ex : `v-if` vs `ng-if`). Cela est dû au fait qu'il y a beaucoup de choses pour lesquelles AngularJS a vu juste et que cela a été une source d'inspiration pour Vue très tôt dans son développement. Cependant, AngularJS vient également avec de nombreux soucis. C'est là que Vue a tenté d'apporter une amélioration significative. @@ -178,7 +182,7 @@ Les deux frameworks sont exceptionnellement rapides avec des métriques similair ### Taille -Les versions récentes d'Angular, avec une [compilation anticipée](https://fr.wikipedia.org/wiki/Compilation_anticip%C3%A9e) et du [tree-shaking](https://en.wikipedia.org/wiki/Tree_shaking) sont capables de diminuer leurs tailles considérablement. Cependant, un projet complet Vue 2, avec Vuex et Vue Router inclus (~30ko gzippé), est toujours significativement plus léger qu'une application avec compilation anticipée et générée par `angular-cli` (~130ko gzippée). +Les versions récentes d'Angular, avec une [compilation anticipée](https://fr.wikipedia.org/wiki/Compilation_anticip%C3%A9e) et du [tree-shaking](https://en.wikipedia.org/wiki/Tree_shaking), sont capables de diminuer considérablement leurs tailles en sortie. Cependant, un projet complet Vue 2, avec Vuex et Vue Router inclus (~30ko gzippé), est toujours significativement plus léger qu'une application avec compilation anticipée et générée par `angular-cli` (~65ko gzippée). ### Flexibilité diff --git a/src/v2/guide/components-custom-events.md b/src/v2/guide/components-custom-events.md index 7836b30720..59a34fdec1 100644 --- a/src/v2/guide/components-custom-events.md +++ b/src/v2/guide/components-custom-events.md @@ -51,7 +51,7 @@ Vue.component('base-checkbox', { À présent, quand vous utilisez `v-model` sur ce composant : -```js +```html ``` diff --git a/src/v2/guide/components-props.md b/src/v2/guide/components-props.md index 1f620e6e3e..dcc5579998 100644 --- a/src/v2/guide/components-props.md +++ b/src/v2/guide/components-props.md @@ -25,7 +25,29 @@ Vue.component('blog-post', { Again, if you're using string templates, this limitation does not apply. -## Static and Dynamic Props +## Prop Types + +So far, we've only seen props listed as an array of strings: + +```js +props: ['title', 'likes', 'isPublished', 'commentIds', 'author'] +``` + +Usually though, you'll want every prop to be a specific type of value. In these cases, you can list props as an object, where the properties' names and values contain the prop names and types, respectively: + +```js +props: { + title: String, + likes: Number, + isPublished: Boolean, + commentIds: Array, + author: Object +} +``` + +This not only documents your component, but will also warn users in the browser's JavaScript console if they pass the wrong type. You'll learn much more about [type checks and other prop validations](#Prop-Validation) further down this page. + +## Passing Static or Dynamic Props So far, you've seen props passed a static value, like in: @@ -36,7 +58,11 @@ So far, you've seen props passed a static value, like in: You've also seen props assigned dynamically with `v-bind`, such as in: ```html + + + + ``` In the two examples above, we happen to pass string values, but _any_ type of value can actually be passed to a prop. @@ -56,14 +82,14 @@ In the two examples above, we happen to pass string values, but _any_ type of va ```html - + - + - + ``` ### Passing an Array @@ -82,10 +108,10 @@ In the two examples above, we happen to pass string values, but _any_ type of va ```html - + - + ``` ### Passing the Properties of an Object @@ -148,7 +174,7 @@ There are usually two cases where it's tempting to mutate a prop: ## Prop Validation -Components can specify requirements for its props. If a requirement isn't met, Vue will warn you in the browser's JavaScript console. This is especially useful when developing a component that's intended to be used by others. +Components can specify requirements for its props, such as the types you've already seen. If a requirement isn't met, Vue will warn you in the browser's JavaScript console. This is especially useful when developing a component that's intended to be used by others. To specify prop validations, you can provide an object with validation requirements to the value of `props`, instead of an array of strings. For example: @@ -200,9 +226,10 @@ The `type` can be one of the following native constructors: - String - Number - Boolean -- Function -- Object - Array +- Object +- Date +- Function - Symbol In addition, `type` can also be a custom constructor function and the assertion will be made with an `instanceof` check. For example, given the following constructor function exists: diff --git a/src/v2/guide/components.md b/src/v2/guide/components.md index 526591fd0c..12f51b6e6d 100644 --- a/src/v2/guide/components.md +++ b/src/v2/guide/components.md @@ -210,25 +210,64 @@ C'est tout ce que vous avez besoin de savoir à propos des props pour le moment, Quand nous réalisons un composant ``, votre template va éventuellement contenir plus que juste le titre : ```html -

{{ post.title }}

+

{{ title }}

``` Vous allez au moins vouloir inclure le contenu du billet : ```html -

{{ post.title }}

-
+

{{ title }}

+
``` Si vous essayez cela dans votre template cependant, Vue va afficher une erreur, expliquant que **tout composant doit avoir un unique élément racine**. Vous pouvez fixer cette erreur en imbriquant le template dans un élément parent comme : ```html
-

{{ post.title }}

-
+

{{ title }}

+
``` +À mesure que nos composants grandissent, il ne sera plus question uniquement d'un titre et d'un contenu pour le billet, mais également de la date de publication, des commentaires et bien plus. Définir une prop indépendamment pour chaque information pourrait devenir gênant : + +```html + +``` + +Le temps sera alors venu de refactoriser le composant `` pour accepter une propriété `post` unique à la place : + +```html + +``` + +```js +Vue.component('blog-post', { + props: ['post'], + template: ` +
+

{{ post.title }}

+
+
+ ` +}) +``` + +

L'exemple ci-dessus et plusieurs exemples par la suite utilisent une chaîne de caractères JavaScript appelée [modèles de libellés](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (« template string ») permettant des templates multilignes plus lisibles. Ceux-ci ne sont pas supportés dans Internet Explorer (IE), aussi, si vous souhaitez supporter IE sans utiliser de transpilateur (p. ex. Babel ou TypeScript), [ajoutez un caractère d'échappement à chaque nouvelle ligne](https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript) à la place.

+ +Maintenant, chaque fois qu'une nouvelle propriété sera ajoutée à l'objet `post`, elle sera automatiquement disponible dans ``. + ## Envoyer des messages aux parents avec les évènements Lors de notre développement du composant ``, plusieurs fonctionnalités vont demander de communiquer des informations au parent. Par exemple, nous pourrions décider d'inclure une fonctionnalité d'accessibilité pour élargir le texte du billet de blog, alors que le reste de la page resterait dans sa taille par défaut : @@ -276,8 +315,6 @@ Vue.component('blog-post', { }) ``` -

L'exemple ci-dessus et plusieurs exemples futurs utilisent une chaine de caractère JavaScript appelée [modèles de libellés](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) permettant des templates multilignes plus lisibles. Ceux-ci ne sont pas supportés dans Internet Explorer (IE), aussi, si vous souhaitez supporter IE sans utiliser de transpilleur (p. ex. Babel ou TypeScript), [échappez le caractère de nouvelle ligne](https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript) à la place.

- Le problème est que le bouton ne fait rien du tout : ```html @@ -438,7 +475,7 @@ Exactement comme les éléments HTML, il est souvent utile de passer du contenu ``` html - Quelque chose c'est mal passé. + Quelque chose s'est mal passé. ``` @@ -447,7 +484,7 @@ Qui pourrait faire le rendu de quelque chose comme : {% raw %}
- Quelque chose c'est mal passé. + Quelque chose s'est mal passé.
+ ``` Vous pouvez parcourir la source du package npm à l'adresse : [cdn.jsdelivr.net/npm/vue](https://cdn.jsdelivr.net/npm/vue/). diff --git a/src/v2/guide/join.md b/src/v2/guide/join.md index 69e5fb63a7..8cd7226f4b 100644 --- a/src/v2/guide/join.md +++ b/src/v2/guide/join.md @@ -13,7 +13,8 @@ Maintenant nous allons voir ensemble ce que la communauté peut faire pour vous ### Obtenir de l'aide - [Forum](https://forum.vuejs.org/french) : Le meilleur endroit pour poser des questions et obtenir des réponses à propos de Vue et de son écosystème. -- [Chat](https://discordapp.com/channels/325477692906536972/360669119948783616) | [En](https://chat.vuejs.org/) : Un lieu pour rencontrer et discuter avec des développeurs. +- [Chat](https://discordapp.com/channels/325477692906536972/360669119948783616) | [En](https://chat.vuejs.org/) : Un endroit où les développeurs peuvent se rencontrer et discuter en temps réel. +- [Meetups](https://www.vuemeetups.org): Envie de rencontrer des utilisateurs de Vue.js enthousiastes comme vous ? Intéressé pour devenir un leader de communauté ? Nous avons l'aide et le support qu'il vous faut juste ici ! - [GitHub](https://github.com/vuejs) : Si vous avez un bogue à reporter ou une demande de nouvelle fonctionnalité à faire, les rapports de bogue (« issues ») GitHub sont là pour ça. Les propositions de fusion (« pull requests ») sont également les bienvenues ! ### Explorer l'écosystème @@ -40,7 +41,7 @@ Après cela, vous serez fin prêt à contribuer sur les dépôts principaux de V Hormis répondre aux questions ou partager des ressources sur le forum et le chat, il y a beaucoup d'autres manières d'améliorer et partager vos connaissances : - **Partagez des ressources pour l'apprentissage.** On dit souvent que la meilleure manière d'apprendre est d'enseigner. Si vous faites quelque chose d'intéressant avec Vue, renforcez votre expertise en écrivant un billet de blog, en proposant des travaux pratiques ou même en publiant un gist sur les réseaux sociaux. -- **Surveillez les dépôts qui vous tiennent à cœur.** Cela vous enverra des notifications dès qu'il y aura une activité dans le dépôt, vous permettant de suivre les discussions en cours et les fonctionnalités à venir. C'est une approche très intéressante pour consolider votre expertise tout en aidant à résoudre les bogues des rapports et les propositions de fusion. +- **Surveillez les dépôts qui vous tiennent à cœur.** Cela vous enverra des notifications dès qu'il y aura une activité dans le dépôt, vous permettant de suivre les discussions en cours et les fonctionnalités à venir. C'est une approche très intéressante pour consolider votre expertise tout en aidant à résoudre les bogues des rapports et les propositions de fusion (« pull request »). ### Traduire les documentations @@ -48,4 +49,14 @@ Vue s'est déjà répandu à travers le monde avec l'équipe principale présent Nous espérons qu'en ce moment, vous êtes en train de lire cette phrase dans votre langue préférée. Si ce n'est pas le cas, que diriez-vous de nous aider à changer cela en répliquant le [dépôt international](https://github.com/vuejs/vuejs.org/) ? -Et si maintenir la traduction que vous êtes en train de lire vous intéresse, n'hésitez pas à répliquer le [dépôt français](https://github.com/vuejs-fr/vuejs.org/) et à proposer vos traductions ou corrections en propositions de fusion. +Et si maintenir la traduction que vous êtes en train de lire vous intéresse (ou toutes les autres traductions officielles d'ailleurs), n'hésitez pas à répliquer le [dépôt français](https://github.com/vuejs-fr/vuejs.org/) et à proposer vos traductions ou corrections en propositions de fusion (« pull request »). + +### Devenir un leader de communauté + +Il y a beaucoup de choses que vous pouvez faire pour aider Vue à grandir dans votre communauté : + +- **Le présenter lors de vos meetup locaux.** Chaque fois que vous donnez un talk ou que vous faites un workshop, vous apportez beaucoup de valeur à la communauté en aidant aussi bien les nouveaux développeurs que les plus expérimentés. +- **Lancez votre propre meetup.** S'il n'y a pas déjà un meetup Vue dans votre zone, vous pouvez créer le votre ! Utilisez [les outils vuemeetups.org](https://www.vuemeetups.org/resources/#introduction) pour vous aider à réussir ! +- **Aider les organisateurs de meetup.** Il n'y a jamais assez d'aide quand il s'agit de mettre en place un évènement, donc vous pouvez donner un coup de main pour aider vos organisateurs locaux pour aider à faire de chaque évènement un succès. + +Si vous avez la moindre question sur comment être plus impliqué dans votre communauté Vue locale, contactez [hello@vuemeetups.org](mailto:hello@vuemeetups.org) ou [@VueMeetups](https://www.twitter.com/vuemeetups) ! diff --git a/src/v2/guide/list.md b/src/v2/guide/list.md index 32f42dca50..e241fe159d 100644 --- a/src/v2/guide/list.md +++ b/src/v2/guide/list.md @@ -432,7 +432,7 @@ De la même manière qu'avec `v-if`, vous pouvez également utiliser la balise `
``` @@ -489,11 +489,15 @@ Voici un exemple complet d'une simple liste de tâches : ``` html
- +
+ + + +
  • \ {{ title }}\ - \ + \
  • \ ', props: ['title'] @@ -553,11 +557,15 @@ new Vue({ {% raw %}
    - +
    + + + +
    • \ {{ title }}\ - \ + \
    • \ ', props: ['title'] diff --git a/src/v2/guide/single-file-components.md b/src/v2/guide/single-file-components.md index 3089032682..e493098c3b 100644 --- a/src/v2/guide/single-file-components.md +++ b/src/v2/guide/single-file-components.md @@ -19,7 +19,7 @@ Tous ces désavantages sont résolus par les **composants monofichiers** avec un Voici un exemple simple de fichier que nous appellerons `Hello.vue` : - +Exemple d'un composant pour un seul fichier (cliquez pour voir le code sous forme de texte) Maintenant nous avons : @@ -29,7 +29,7 @@ Maintenant nous avons : Et comme promis, nous pouvons aussi utiliser des préprocesseurs tels que Pug, Babel (avec les modules ES2015), et Stylus pour obtenir des composants plus lisibles et plus riches en fonctionnalités. - +Exemple d'un composant pour un seul fichier avec des préprocesseurs (cliquez pour voir le code sous forme de texte) Ces langages spécifiques ne sont que des exemples; vous pourriez tout aussi aisément utiliser Bublé, Typescript, SCSS, PostCSS - ou tout autre préprocesseur qui vous aide à être productif. Si vous utilisez webpack avec `vue-loader`, vous aurez aussi un outil de premier choix pour les modules CSS. diff --git a/src/v2/guide/transitions.md b/src/v2/guide/transitions.md index 86be067da0..881895aba7 100644 --- a/src/v2/guide/transitions.md +++ b/src/v2/guide/transitions.md @@ -955,6 +955,7 @@ Jusqu'à présent, nous avons réalisé des transitions pour : Alors, qu'en est-il lorsque nous avons une liste complète d'éléments où nous voulons faire un rendu simultané, par exemple avec `v-for` ? Dans ce cas, nous allons utiliser le composant ``. Cependant avant de plonger dans un exemple, il y a quelques éléments importants à connaitre sur ce composant : - Contrairement à ``, il rend un élément réel : par défaut un ``. Vous pouvez modifier l'élément rendu avec l'attribut `tag`. + - [Les modes de transition](#Les-modes-de-transition) ne sont pas disponibles car nous ne pouvons plus alterner entre des éléments mutuellement exclusifs. - Les éléments à l'intérieur **doivent toujours avoir** un attribut `key` unique ### Transitions de liste entrantes/sortantes diff --git a/src/v2/guide/typescript.md b/src/v2/guide/typescript.md index 2b7268a5d6..47d067176d 100644 --- a/src/v2/guide/typescript.md +++ b/src/v2/guide/typescript.md @@ -12,8 +12,6 @@ Un système de typage statique peut aider à prévenir des erreurs d'exécutions Puisque ceux-ci sont [publiés sur npm](https://cdn.jsdelivr.net/npm/vue/types/), et que la dernière version de TypeScript sait comment résoudre des déclarations de type dans des packages npm, cela signifie qu'installer ceux-ci via npm ne requiert aucun outil supplémentaire pour utiliser TypeScript avec Vue. -Nous avons également planifié de fournir prochainement une option dans `vue-cli` pour installer un projet Vue + TypeScript prêt à l'emploi. - ## Configuration recommandée ``` js @@ -37,9 +35,21 @@ Voir [les options de compilation TypeScript](https://www.typescriptlang.org/docs ## Outils de développement -Pour développer des applications Vue avec TypeScript, nous recommandons fortement d'utiliser [Visual Studio Code](https://code.visualstudio.com/) qui fournit un support de TypeScript nativement. +### Creation de projet + +[Vue CLI 3](https://github.com/vuejs/vue-cli) peut générer de nouveaux projets qui utilise TypeScript. Pour commencer : + +```bash +# 1. Installer Vue CLI s'il n'est pas déjà installé +npm install --global @vue/cli + +# 2. Créer un nouveau projet et choisir l'option "Manually select features" +vue create my-project-name +``` + +### Support d'édition -Si vous utilisez des [composants monofichiers](./single-file-components.html), utilisez la super [extension Vetur](https://github.com/vuejs/vetur) qui fournit des déductions TypeScript à l'intérieur de vos composants monofichiers et bien d'autres fonctionnalités extras. +Pour développer des applications Vue avec TypeScript, nous recommandons fortement d'utiliser [Visual Studio Code](https://code.visualstudio.com/) qui fournit un support de TypeScript nativement. Si vous utilisez des [composants monofichiers](./single-file-components.html), utilisez la super [extension Vetur](https://github.com/vuejs/vetur) qui fournit des déductions TypeScript à l'intérieur de vos composants monofichiers et bien d'autres fonctionnalités extras. [WebStorm](https://www.jetbrains.com/webstorm/) fournit également un support de base pour TypeScript et Vue.js. diff --git a/src/v2/guide/unit-testing.md b/src/v2/guide/unit-testing.md index 3bebec9c73..e399cbf119 100644 --- a/src/v2/guide/unit-testing.md +++ b/src/v2/guide/unit-testing.md @@ -131,4 +131,4 @@ it('met à jour le message rendu quand `vm.message` est mis à jour', done => { Nous prévoyons de travailler sur une collection de fonctions utilitaires de tests communs pour rendre encore plus simple le rendu de composants avec différentes contraintes (par ex. des rendus peu profonds ignorant les composants enfants) et faire des assertions sur le code en sortie. -Pour des informations plus pointues sur les tests unitaires avec Vue, jeter un œil à [vue-test-utils](https://vue-test-utils.vuejs.org/fr/) et notre entrée du Cookbook à propos des [tests unitaires de composants Vue](https://vuejs.org/v2/cookbook/unit-testing-vue-components.html). +Pour des informations plus pointues sur les tests unitaires avec Vue, jeter un œil à [vue-test-utils](https://vue-test-utils.vuejs.org/fr/) et notre entrée des tutoriels à propos des [tests unitaires de composants Vue](https://vuejs.org/v2/cookbook/unit-testing-vue-components.html). \ No newline at end of file diff --git a/src/v2/style-guide/index.md b/src/v2/style-guide/index.md index 493455069a..78eb7e8cdd 100644 --- a/src/v2/style-guide/index.md +++ b/src/v2/style-guide/index.md @@ -1514,6 +1514,16 @@ Voici l'ordre par défaut que nous recommandons pour les options de composant. E 9. **Évènements** (fonctions de rappel déclenchées par des évènements réactifs) - `watch` - Évènements du cycle de vie (dans leur ordre d'appel) + - `beforeCreate` + - `created` + - `beforeMount` + - `mounted` + - `beforeUpdate` + - `updated` + - `activated` + - `deactivated` + - `beforeDestroy` + - `destroyed` 10. **Propriétés non réactives** (propriétés d'instance indépendantes du système de réactivité) - `methods` diff --git a/themes/vue/_config.yml b/themes/vue/_config.yml index 18ac8df26d..a7f928612c 100644 --- a/themes/vue/_config.yml +++ b/themes/vue/_config.yml @@ -1,7 +1,7 @@ site_description: "Vue.js - Le Framework JavaScript Évolutif" google_analytics: UA-46852172-1 root_domain: vuejs.org -vue_version: 2.5.13 +vue_version: 2.5.16 special_sponsors: - url: https://stdlib.com @@ -60,6 +60,10 @@ gold_sponsors: - url: https://www.pubnub.com/vue-js/ img: pubnub.png +silver_sponsors: + - url: https://dopamine.bg/ + img: dopamine.png + bronze_sponsors: - url: http://tighten.co/ img: http://i.imgur.com/T7fQYLT.png diff --git a/themes/vue/layout/layout.ejs b/themes/vue/layout/layout.ejs index f460a72ad7..77b6689743 100644 --- a/themes/vue/layout/layout.ejs +++ b/themes/vue/layout/layout.ejs @@ -58,7 +58,10 @@ - +
    diff --git a/themes/vue/layout/sponsors-page.ejs b/themes/vue/layout/sponsors-page.ejs index ede3ab7952..27ee5b207a 100644 --- a/themes/vue/layout/sponsors-page.ejs +++ b/themes/vue/layout/sponsors-page.ejs @@ -121,6 +121,16 @@ Les soutiens récurrents viennent avec des avantages exclusifs comme avoir son n <%_ } _%>

    +

    Patreon Silver

    + + +

    Si vous êtes une entreprise et que vous utilisez Vue pour des produits générant du revenu, cela fait sens d'être sponsor du développement de Vue : cela assure que le projet sur lequel repose votre produit reste sain et activement maintenu. Cela améliore également votre visibilité auprès de la communauté Vue et vous rend plus attractif pour les développeurs Vue.

    diff --git a/themes/vue/source/css/_sponsors-page.styl b/themes/vue/source/css/_sponsors-page.styl index 77b397e982..2052feda2b 100644 --- a/themes/vue/source/css/_sponsors-page.styl +++ b/themes/vue/source/css/_sponsors-page.styl @@ -23,8 +23,10 @@ .open-collective-sponsors img - max-height 80px - margin-right 20px + max-width 140px + max-height 60px + margin-right 30px + margin-bottom 20px #one-time-donations a, svg diff --git a/themes/vue/source/images/dopamine.png b/themes/vue/source/images/dopamine.png new file mode 100644 index 0000000000..3d688c7a55 Binary files /dev/null and b/themes/vue/source/images/dopamine.png differ diff --git a/themes/vue/source/js/vue.js b/themes/vue/source/js/vue.js index 9d84c53b4b..657cb37eaa 100644 --- a/themes/vue/source/js/vue.js +++ b/themes/vue/source/js/vue.js @@ -1,6 +1,6 @@ /*! - * Vue.js v2.5.13 - * (c) 2014-2017 Evan You + * Vue.js v2.5.16 + * (c) 2014-2018 Evan You * Released under the MIT License. */ (function (global, factory) { @@ -185,9 +185,15 @@ var hyphenate = cached(function (str) { }); /** - * Simple bind, faster than native + * Simple bind polyfill for environments that do not support it... e.g. + * PhantomJS 1.x. Technically we don't need this anymore since native bind is + * now more performant in most browsers, but removing it would be breaking for + * code that was able to run in PhantomJS 1.x, so this must be kept for + * backwards compatibility. */ -function bind (fn, ctx) { + +/* istanbul ignore next */ +function polyfillBind (fn, ctx) { function boundFn (a) { var l = arguments.length; return l @@ -196,11 +202,19 @@ function bind (fn, ctx) { : fn.call(ctx, a) : fn.call(ctx) } - // record original fn length + boundFn._length = fn.length; return boundFn } +function nativeBind (fn, ctx) { + return fn.bind(ctx) +} + +var bind = Function.prototype.bind + ? nativeBind + : polyfillBind; + /** * Convert an Array-like object to a real Array. */ @@ -430,7 +444,7 @@ var config = ({ * Exposed for legacy reasons */ _lifecycleHooks: LIFECYCLE_HOOKS -}); +}) /* */ @@ -474,7 +488,6 @@ function parsePath (path) { /* */ - // can we use __proto__? var hasProto = '__proto__' in {}; @@ -513,7 +526,7 @@ var _isServer; var isServerRendering = function () { if (_isServer === undefined) { /* istanbul ignore if */ - if (!inBrowser && typeof global !== 'undefined') { + if (!inBrowser && !inWeex && typeof global !== 'undefined') { // detect presence of vue-server-renderer and avoid // Webpack shimming the process _isServer = global['process'].env.VUE_ENV === 'server'; @@ -770,8 +783,7 @@ function createTextVNode (val) { // used for static nodes and slot nodes because they may be reused across // multiple renders, cloning them avoids errors when DOM manipulations rely // on their elm reference. -function cloneVNode (vnode, deep) { - var componentOptions = vnode.componentOptions; +function cloneVNode (vnode) { var cloned = new VNode( vnode.tag, vnode.data, @@ -779,7 +791,7 @@ function cloneVNode (vnode, deep) { vnode.text, vnode.elm, vnode.context, - componentOptions, + vnode.componentOptions, vnode.asyncFactory ); cloned.ns = vnode.ns; @@ -790,33 +802,18 @@ function cloneVNode (vnode, deep) { cloned.fnOptions = vnode.fnOptions; cloned.fnScopeId = vnode.fnScopeId; cloned.isCloned = true; - if (deep) { - if (vnode.children) { - cloned.children = cloneVNodes(vnode.children, true); - } - if (componentOptions && componentOptions.children) { - componentOptions.children = cloneVNodes(componentOptions.children, true); - } - } return cloned } -function cloneVNodes (vnodes, deep) { - var len = vnodes.length; - var res = new Array(len); - for (var i = 0; i < len; i++) { - res[i] = cloneVNode(vnodes[i], deep); - } - return res -} - /* * not type checking this file because flow doesn't play well with * dynamically accessing methods on Array prototype */ var arrayProto = Array.prototype; -var arrayMethods = Object.create(arrayProto);[ +var arrayMethods = Object.create(arrayProto); + +var methodsToPatch = [ 'push', 'pop', 'shift', @@ -824,7 +821,12 @@ var arrayMethods = Object.create(arrayProto);[ 'splice', 'sort', 'reverse' -].forEach(function (method) { +]; + +/** + * Intercept mutating methods and emit events + */ +methodsToPatch.forEach(function (method) { // cache original method var original = arrayProto[method]; def(arrayMethods, method, function mutator () { @@ -855,20 +857,20 @@ var arrayMethods = Object.create(arrayProto);[ var arrayKeys = Object.getOwnPropertyNames(arrayMethods); /** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However when passing down props, - * we don't want to force conversion because the value may be a nested value - * under a frozen data structure. Converting it would defeat the optimization. + * In some cases we may want to disable observation inside a component's + * update computation. */ -var observerState = { - shouldConvert: true -}; +var shouldObserve = true; + +function toggleObserving (value) { + shouldObserve = value; +} /** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target * object's property keys into getter/setters that - * collect dependencies and dispatches updates. + * collect dependencies and dispatch updates. */ var Observer = function Observer (value) { this.value = value; @@ -894,7 +896,7 @@ var Observer = function Observer (value) { Observer.prototype.walk = function walk (obj) { var keys = Object.keys(obj); for (var i = 0; i < keys.length; i++) { - defineReactive(obj, keys[i], obj[keys[i]]); + defineReactive(obj, keys[i]); } }; @@ -944,7 +946,7 @@ function observe (value, asRootData) { if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__; } else if ( - observerState.shouldConvert && + shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && @@ -977,6 +979,9 @@ function defineReactive ( // cater for pre-defined getter/setters var getter = property && property.get; + if (!getter && arguments.length === 2) { + val = obj[key]; + } var setter = property && property.set; var childOb = !shallow && observe(val); @@ -1023,6 +1028,11 @@ function defineReactive ( * already exist. */ function set (target, key, val) { + if ("development" !== 'production' && + (isUndef(target) || isPrimitive(target)) + ) { + warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); + } if (Array.isArray(target) && isValidArrayIndex(key)) { target.length = Math.max(target.length, key); target.splice(key, 1, val); @@ -1053,6 +1063,11 @@ function set (target, key, val) { * Delete a property and trigger change if necessary. */ function del (target, key) { + if ("development" !== 'production' && + (isUndef(target) || isPrimitive(target)) + ) { + warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); + } if (Array.isArray(target) && isValidArrayIndex(key)) { target.splice(key, 1); return @@ -1519,12 +1534,18 @@ function validateProp ( var prop = propOptions[key]; var absent = !hasOwn(propsData, key); var value = propsData[key]; - // handle boolean props - if (isType(Boolean, prop.type)) { + // boolean casting + var booleanIndex = getTypeIndex(Boolean, prop.type); + if (booleanIndex > -1) { if (absent && !hasOwn(prop, 'default')) { value = false; - } else if (!isType(String, prop.type) && (value === '' || value === hyphenate(key))) { - value = true; + } else if (value === '' || value === hyphenate(key)) { + // only cast empty string / same name to boolean if + // boolean has higher priority + var stringIndex = getTypeIndex(String, prop.type); + if (stringIndex < 0 || booleanIndex < stringIndex) { + value = true; + } } } // check default value @@ -1532,10 +1553,10 @@ function validateProp ( value = getPropDefaultValue(vm, prop, key); // since the default value is a fresh copy, // make sure to observe it. - var prevShouldConvert = observerState.shouldConvert; - observerState.shouldConvert = true; + var prevShouldObserve = shouldObserve; + toggleObserving(true); observe(value); - observerState.shouldConvert = prevShouldConvert; + toggleObserving(prevShouldObserve); } { assertProp(prop, key, value, vm, absent); @@ -1664,17 +1685,20 @@ function getType (fn) { return match ? match[1] : '' } -function isType (type, fn) { - if (!Array.isArray(fn)) { - return getType(fn) === getType(type) +function isSameType (a, b) { + return getType(a) === getType(b) +} + +function getTypeIndex (type, expectedTypes) { + if (!Array.isArray(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1 } - for (var i = 0, len = fn.length; i < len; i++) { - if (getType(fn[i]) === getType(type)) { - return true + for (var i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i } } - /* istanbul ignore next */ - return false + return -1 } /* */ @@ -1737,19 +1761,19 @@ function flushCallbacks () { } } -// Here we have async deferring wrappers using both micro and macro tasks. -// In < 2.4 we used micro tasks everywhere, but there are some scenarios where -// micro tasks have too high a priority and fires in between supposedly +// Here we have async deferring wrappers using both microtasks and (macro) tasks. +// In < 2.4 we used microtasks everywhere, but there are some scenarios where +// microtasks have too high a priority and fire in between supposedly // sequential events (e.g. #4521, #6690) or even between bubbling of the same -// event (#6566). However, using macro tasks everywhere also has subtle problems +// event (#6566). However, using (macro) tasks everywhere also has subtle problems // when state is changed right before repaint (e.g. #6813, out-in transitions). -// Here we use micro task by default, but expose a way to force macro task when +// Here we use microtask by default, but expose a way to force (macro) task when // needed (e.g. in event handlers attached by v-on). var microTimerFunc; var macroTimerFunc; var useMacroTask = false; -// Determine (macro) Task defer implementation. +// Determine (macro) task defer implementation. // Technically setImmediate should be the ideal choice, but it's only available // in IE. The only polyfill that consistently queues the callback after all DOM // events triggered in the same loop is by using MessageChannel. @@ -1776,7 +1800,7 @@ if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { }; } -// Determine MicroTask defer implementation. +// Determine microtask defer implementation. /* istanbul ignore next, $flow-disable-line */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); @@ -1796,7 +1820,7 @@ if (typeof Promise !== 'undefined' && isNative(Promise)) { /** * Wrap a function so that if any code inside triggers state change, - * the changes are queued using a Task instead of a MicroTask. + * the changes are queued using a (macro) task instead of a microtask. */ function withMacroTask (fn) { return fn._withTask || (fn._withTask = function () { @@ -1885,8 +1909,7 @@ var initProxy; }; var hasProxy = - typeof Proxy !== 'undefined' && - Proxy.toString().match(/native code/); + typeof Proxy !== 'undefined' && isNative(Proxy); if (hasProxy) { var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); @@ -1954,7 +1977,7 @@ function traverse (val) { function _traverse (val, seen) { var i, keys; var isA = Array.isArray(val); - if ((!isA && !isObject(val)) || Object.isFrozen(val)) { + if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { return } if (val.__ob__) { @@ -2812,29 +2835,30 @@ function updateChildComponent ( // update $attrs and $listeners hash // these are also reactive so they may trigger child update if the child // used them during render - vm.$attrs = (parentVnode.data && parentVnode.data.attrs) || emptyObject; + vm.$attrs = parentVnode.data.attrs || emptyObject; vm.$listeners = listeners || emptyObject; // update props if (propsData && vm.$options.props) { - observerState.shouldConvert = false; + toggleObserving(false); var props = vm._props; var propKeys = vm.$options._propKeys || []; for (var i = 0; i < propKeys.length; i++) { var key = propKeys[i]; - props[key] = validateProp(key, vm.$options.props, propsData, vm); + var propOptions = vm.$options.props; // wtf flow? + props[key] = validateProp(key, propOptions, propsData, vm); } - observerState.shouldConvert = true; + toggleObserving(true); // keep a copy of raw propsData vm.$options.propsData = propsData; } // update listeners - if (listeners) { - var oldListeners = vm.$options._parentListeners; - vm.$options._parentListeners = listeners; - updateComponentListeners(vm, listeners, oldListeners); - } + listeners = listeners || emptyObject; + var oldListeners = vm.$options._parentListeners; + vm.$options._parentListeners = listeners; + updateComponentListeners(vm, listeners, oldListeners); + // resolve slots + force update if has children if (hasChildren) { vm.$slots = resolveSlots(renderChildren, parentVnode.context); @@ -2888,6 +2912,8 @@ function deactivateChildComponent (vm, direct) { } function callHook (vm, hook) { + // #7573 disable dep collection when invoking lifecycle hooks + pushTarget(); var handlers = vm.$options[hook]; if (handlers) { for (var i = 0, j = handlers.length; i < j; i++) { @@ -2901,6 +2927,7 @@ function callHook (vm, hook) { if (vm._hasHookEvent) { vm.$emit('hook:' + hook); } + popTarget(); } /* */ @@ -3045,7 +3072,7 @@ function queueWatcher (watcher) { /* */ -var uid$2 = 0; +var uid$1 = 0; /** * A watcher parses an expression, collects dependencies, @@ -3074,7 +3101,7 @@ var Watcher = function Watcher ( this.deep = this.user = this.lazy = this.sync = false; } this.cb = cb; - this.id = ++uid$2; // uid for batching + this.id = ++uid$1; // uid for batching this.active = true; this.dirty = this.lazy; // for lazy watchers this.deps = []; @@ -3297,7 +3324,9 @@ function initProps (vm, propsOptions) { var keys = vm.$options._propKeys = []; var isRoot = !vm.$parent; // root instance props should be converted - observerState.shouldConvert = isRoot; + if (!isRoot) { + toggleObserving(false); + } var loop = function ( key ) { keys.push(key); var value = validateProp(key, propsOptions, propsData, vm); @@ -3332,7 +3361,7 @@ function initProps (vm, propsOptions) { }; for (var key in propsOptions) loop( key ); - observerState.shouldConvert = true; + toggleObserving(true); } function initData (vm) { @@ -3378,11 +3407,15 @@ function initData (vm) { } function getData (data, vm) { + // #7573 disable dep collection when invoking data getters + pushTarget(); try { return data.call(vm, vm) } catch (e) { handleError(e, vm, "data()"); return {} + } finally { + popTarget(); } } @@ -3520,7 +3553,7 @@ function initWatch (vm, watch) { function createWatcher ( vm, - keyOrFn, + expOrFn, handler, options ) { @@ -3531,7 +3564,7 @@ function createWatcher ( if (typeof handler === 'string') { handler = vm[handler]; } - return vm.$watch(keyOrFn, handler, options) + return vm.$watch(expOrFn, handler, options) } function stateMixin (Vue) { @@ -3595,7 +3628,7 @@ function initProvide (vm) { function initInjections (vm) { var result = resolveInject(vm.$options.inject, vm); if (result) { - observerState.shouldConvert = false; + toggleObserving(false); Object.keys(result).forEach(function (key) { /* istanbul ignore else */ { @@ -3609,7 +3642,7 @@ function initInjections (vm) { }); } }); - observerState.shouldConvert = true; + toggleObserving(true); } } @@ -3629,7 +3662,7 @@ function resolveInject (inject, vm) { var provideKey = inject[key].from; var source = vm; while (source) { - if (source._provided && provideKey in source._provided) { + if (source._provided && hasOwn(source._provided, provideKey)) { result[key] = source._provided[provideKey]; break } @@ -3744,6 +3777,14 @@ function resolveFilter (id) { /* */ +function isKeyNotMatch (expect, actual) { + if (Array.isArray(expect)) { + return expect.indexOf(actual) === -1 + } else { + return expect !== actual + } +} + /** * Runtime helper for checking keyCodes from config. * exposed as Vue.prototype._k @@ -3752,16 +3793,15 @@ function resolveFilter (id) { function checkKeyCodes ( eventKeyCode, key, - builtInAlias, - eventKeyName + builtInKeyCode, + eventKeyName, + builtInKeyName ) { - var keyCodes = config.keyCodes[key] || builtInAlias; - if (keyCodes) { - if (Array.isArray(keyCodes)) { - return keyCodes.indexOf(eventKeyCode) === -1 - } else { - return keyCodes !== eventKeyCode - } + var mappedKeyCode = config.keyCodes[key] || builtInKeyCode; + if (builtInKeyName && eventKeyName && !config.keyCodes[key]) { + return isKeyNotMatch(builtInKeyName, eventKeyName) + } else if (mappedKeyCode) { + return isKeyNotMatch(mappedKeyCode, eventKeyCode) } else if (eventKeyName) { return hyphenate(eventKeyName) !== key } @@ -3833,11 +3873,9 @@ function renderStatic ( var cached = this._staticTrees || (this._staticTrees = []); var tree = cached[index]; // if has already-rendered static tree and not inside v-for, - // we can reuse the same tree by doing a shallow clone. + // we can reuse the same tree. if (tree && !isInFor) { - return Array.isArray(tree) - ? cloneVNodes(tree) - : cloneVNode(tree) + return tree } // otherwise, render a fresh tree. tree = cached[index] = this.$options.staticRenderFns[index].call( @@ -3935,6 +3973,24 @@ function FunctionalRenderContext ( Ctor ) { var options = Ctor.options; + // ensure the createElement function in functional components + // gets a unique context - this is necessary for correct named slot check + var contextVm; + if (hasOwn(parent, '_uid')) { + contextVm = Object.create(parent); + // $flow-disable-line + contextVm._original = parent; + } else { + // the context vm passed in is a functional context as well. + // in this case we want to make sure we are able to get a hold to the + // real context instance. + contextVm = parent; + // $flow-disable-line + parent = parent._original; + } + var isCompiled = isTrue(options._compiled); + var needNormalization = !isCompiled; + this.data = data; this.props = props; this.children = children; @@ -3943,12 +3999,6 @@ function FunctionalRenderContext ( this.injections = resolveInject(options.inject, parent); this.slots = function () { return resolveSlots(children, parent); }; - // ensure the createElement function in functional components - // gets a unique context - this is necessary for correct named slot check - var contextVm = Object.create(parent); - var isCompiled = isTrue(options._compiled); - var needNormalization = !isCompiled; - // support for compiled functional template if (isCompiled) { // exposing $options for renderStatic() @@ -3961,7 +4011,7 @@ function FunctionalRenderContext ( if (options._scopeId) { this._c = function (a, b, c, d) { var vnode = createElement(contextVm, a, b, c, d, needNormalization); - if (vnode) { + if (vnode && !Array.isArray(vnode)) { vnode.fnScopeId = options._scopeId; vnode.fnContext = parent; } @@ -4004,14 +4054,28 @@ function createFunctionalComponent ( var vnode = options.render.call(null, renderContext._c, renderContext); if (vnode instanceof VNode) { - vnode.fnContext = contextVm; - vnode.fnOptions = options; - if (data.slot) { - (vnode.data || (vnode.data = {})).slot = data.slot; + return cloneAndMarkFunctionalResult(vnode, data, renderContext.parent, options) + } else if (Array.isArray(vnode)) { + var vnodes = normalizeChildren(vnode) || []; + var res = new Array(vnodes.length); + for (var i = 0; i < vnodes.length; i++) { + res[i] = cloneAndMarkFunctionalResult(vnodes[i], data, renderContext.parent, options); } + return res } +} - return vnode +function cloneAndMarkFunctionalResult (vnode, data, contextVm, options) { + // #7817 clone node before setting fnContext, otherwise if the node is reused + // (e.g. it was from a cached normal slot) the fnContext causes named slots + // that should not be matched to match. + var clone = cloneVNode(vnode); + clone.fnContext = contextVm; + clone.fnOptions = options; + if (data.slot) { + (clone.data || (clone.data = {})).slot = data.slot; + } + return clone } function mergeProps (to, from) { @@ -4041,7 +4105,7 @@ function mergeProps (to, from) { /* */ -// hooks to be invoked on component VNodes during patch +// inline hooks to be invoked on component VNodes during patch var componentVNodeHooks = { init: function init ( vnode, @@ -4049,7 +4113,15 @@ var componentVNodeHooks = { parentElm, refElm ) { - if (!vnode.componentInstance || vnode.componentInstance._isDestroyed) { + if ( + vnode.componentInstance && + !vnode.componentInstance._isDestroyed && + vnode.data.keepAlive + ) { + // kept-alive components, treat as a patch + var mountedNode = vnode; // work around flow + componentVNodeHooks.prepatch(mountedNode, mountedNode); + } else { var child = vnode.componentInstance = createComponentInstanceForVnode( vnode, activeInstance, @@ -4057,10 +4129,6 @@ var componentVNodeHooks = { refElm ); child.$mount(hydrating ? vnode.elm : undefined, hydrating); - } else if (vnode.data.keepAlive) { - // kept-alive components, treat as a patch - var mountedNode = vnode; // work around flow - componentVNodeHooks.prepatch(mountedNode, mountedNode); } }, @@ -4195,8 +4263,8 @@ function createComponent ( } } - // merge component management hooks onto the placeholder node - mergeHooks(data); + // install component management hooks onto the placeholder node + installComponentHooks(data); // return a placeholder vnode var name = Ctor.options.name || tag; @@ -4236,22 +4304,11 @@ function createComponentInstanceForVnode ( return new vnode.componentOptions.Ctor(options) } -function mergeHooks (data) { - if (!data.hook) { - data.hook = {}; - } +function installComponentHooks (data) { + var hooks = data.hook || (data.hook = {}); for (var i = 0; i < hooksToMerge.length; i++) { var key = hooksToMerge[i]; - var fromParent = data.hook[key]; - var ours = componentVNodeHooks[key]; - data.hook[key] = fromParent ? mergeHook$1(ours, fromParent) : ours; - } -} - -function mergeHook$1 (one, two) { - return function (a, b, c, d) { - one(a, b, c, d); - two(a, b, c, d); + hooks[key] = componentVNodeHooks[key]; } } @@ -4368,8 +4425,11 @@ function _createElement ( // direct component options / constructor vnode = createComponent(tag, data, context, children); } - if (isDef(vnode)) { - if (ns) { applyNS(vnode, ns); } + if (Array.isArray(vnode)) { + return vnode + } else if (isDef(vnode)) { + if (isDef(ns)) { applyNS(vnode, ns); } + if (isDef(data)) { registerDeepBindings(data); } return vnode } else { return createEmptyVNode() @@ -4386,13 +4446,26 @@ function applyNS (vnode, ns, force) { if (isDef(vnode.children)) { for (var i = 0, l = vnode.children.length; i < l; i++) { var child = vnode.children[i]; - if (isDef(child.tag) && (isUndef(child.ns) || isTrue(force))) { + if (isDef(child.tag) && ( + isUndef(child.ns) || (isTrue(force) && child.tag !== 'svg'))) { applyNS(child, ns, force); } } } } +// ref #5318 +// necessary to ensure parent re-render when deep bindings like :style and +// :class are used on slot nodes +function registerDeepBindings (data) { + if (isObject(data.style)) { + traverse(data.style); + } + if (isObject(data.class)) { + traverse(data.class); + } +} + /* */ function initRender (vm) { @@ -4441,20 +4514,17 @@ function renderMixin (Vue) { var render = ref.render; var _parentVnode = ref._parentVnode; - if (vm._isMounted) { - // if the parent didn't update, the slot nodes will be the ones from - // last render. They need to be cloned to ensure "freshness" for this render. + // reset _rendered flag on slots for duplicate slot check + { for (var key in vm.$slots) { - var slot = vm.$slots[key]; - // _rendered is a flag added by renderSlot, but may not be present - // if the slot is passed from manually written render functions - if (slot._rendered || (slot[0] && slot[0].elm)) { - vm.$slots[key] = cloneVNodes(slot, true /* deep */); - } + // $flow-disable-line + vm.$slots[key]._rendered = false; } } - vm.$scopedSlots = (_parentVnode && _parentVnode.data.scopedSlots) || emptyObject; + if (_parentVnode) { + vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject; + } // set parent vnode. this allows render functions to have access // to the data on the placeholder node. @@ -4500,13 +4570,13 @@ function renderMixin (Vue) { /* */ -var uid$1 = 0; +var uid$3 = 0; function initMixin (Vue) { Vue.prototype._init = function (options) { var vm = this; // a uid - vm._uid = uid$1++; + vm._uid = uid$3++; var startTag, endTag; /* istanbul ignore if */ @@ -4637,20 +4707,20 @@ function dedupe (latest, extended, sealed) { } } -function Vue$3 (options) { +function Vue (options) { if ("development" !== 'production' && - !(this instanceof Vue$3) + !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword'); } this._init(options); } -initMixin(Vue$3); -stateMixin(Vue$3); -eventsMixin(Vue$3); -lifecycleMixin(Vue$3); -renderMixin(Vue$3); +initMixin(Vue); +stateMixin(Vue); +eventsMixin(Vue); +lifecycleMixin(Vue); +renderMixin(Vue); /* */ @@ -4879,13 +4949,15 @@ var KeepAlive = { } }, - watch: { - include: function include (val) { - pruneCache(this, function (name) { return matches(val, name); }); - }, - exclude: function exclude (val) { - pruneCache(this, function (name) { return !matches(val, name); }); - } + mounted: function mounted () { + var this$1 = this; + + this.$watch('include', function (val) { + pruneCache(this$1, function (name) { return matches(val, name); }); + }); + this.$watch('exclude', function (val) { + pruneCache(this$1, function (name) { return !matches(val, name); }); + }); }, render: function render () { @@ -4933,11 +5005,11 @@ var KeepAlive = { } return vnode || (slot && slot[0]) } -}; +} var builtInComponents = { KeepAlive: KeepAlive -}; +} /* */ @@ -4985,20 +5057,25 @@ function initGlobalAPI (Vue) { initAssetRegisters(Vue); } -initGlobalAPI(Vue$3); +initGlobalAPI(Vue); -Object.defineProperty(Vue$3.prototype, '$isServer', { +Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }); -Object.defineProperty(Vue$3.prototype, '$ssrContext', { +Object.defineProperty(Vue.prototype, '$ssrContext', { get: function get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }); -Vue$3.version = '2.5.13'; +// expose FunctionalRenderContext for ssr runtime helper installation +Object.defineProperty(Vue, 'FunctionalRenderContext', { + value: FunctionalRenderContext +}); + +Vue.version = '2.5.16'; /* */ @@ -5272,8 +5349,8 @@ function setTextContent (node, text) { node.textContent = text; } -function setAttribute (node, key, val) { - node.setAttribute(key, val); +function setStyleScope (node, scopeId) { + node.setAttribute(scopeId, ''); } @@ -5289,7 +5366,7 @@ var nodeOps = Object.freeze({ nextSibling: nextSibling, tagName: tagName, setTextContent: setTextContent, - setAttribute: setAttribute + setStyleScope: setStyleScope }); /* */ @@ -5307,11 +5384,11 @@ var ref = { destroy: function destroy (vnode) { registerRef(vnode, true); } -}; +} function registerRef (vnode, isRemoval) { var key = vnode.data.ref; - if (!key) { return } + if (!isDef(key)) { return } var vm = vnode.context; var ref = vnode.componentInstance || vnode.elm; @@ -5442,7 +5519,25 @@ function createPatchFunction (backend) { } var creatingElmInVPre = 0; - function createElm (vnode, insertedVnodeQueue, parentElm, refElm, nested) { + + function createElm ( + vnode, + insertedVnodeQueue, + parentElm, + refElm, + nested, + ownerArray, + index + ) { + if (isDef(vnode.elm) && isDef(ownerArray)) { + // This vnode was used in a previous render! + // now it's used as a new node, overwriting its elm would cause + // potential patch errors down the road when it's used as an insertion + // reference node. Instead, we clone the node on-demand before creating + // associated DOM element for it. + vnode = ownerArray[index] = cloneVNode(vnode); + } + vnode.isRootInsert = !nested; // for transition enter check if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) { return @@ -5465,6 +5560,7 @@ function createPatchFunction (backend) { ); } } + vnode.elm = vnode.ns ? nodeOps.createElementNS(vnode.ns, tag) : nodeOps.createElement(tag, vnode); @@ -5570,7 +5666,7 @@ function createPatchFunction (backend) { checkDuplicateKeys(children); } for (var i = 0; i < children.length; ++i) { - createElm(children[i], insertedVnodeQueue, vnode.elm, null, true); + createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i); } } else if (isPrimitive(vnode.text)) { nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text))); @@ -5601,12 +5697,12 @@ function createPatchFunction (backend) { function setScope (vnode) { var i; if (isDef(i = vnode.fnScopeId)) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } else { var ancestor = vnode; while (ancestor) { if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } ancestor = ancestor.parent; } @@ -5617,13 +5713,13 @@ function createPatchFunction (backend) { i !== vnode.fnContext && isDef(i = i.$options._scopeId) ) { - nodeOps.setAttribute(vnode.elm, i, ''); + nodeOps.setStyleScope(vnode.elm, i); } } function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) { for (; startIdx <= endIdx; ++startIdx) { - createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm); + createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx); } } @@ -5733,7 +5829,7 @@ function createPatchFunction (backend) { ? oldKeyToIdx[newStartVnode.key] : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx); if (isUndef(idxInOld)) { // New element - createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm); + createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx); } else { vnodeToMove = oldCh[idxInOld]; if (sameVnode(vnodeToMove, newStartVnode)) { @@ -5742,7 +5838,7 @@ function createPatchFunction (backend) { canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm); } else { // same key but different element. treat as new element - createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm); + createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx); } } newStartVnode = newCh[++newStartIdx]; @@ -6080,7 +6176,7 @@ var directives = { destroy: function unbindDirectives (vnode) { updateDirectives(vnode, emptyNode); } -}; +} function updateDirectives (oldVnode, vnode) { if (oldVnode.data.directives || vnode.data.directives) { @@ -6191,7 +6287,7 @@ function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) { var baseModules = [ ref, directives -]; +] /* */ @@ -6237,7 +6333,9 @@ function updateAttrs (oldVnode, vnode) { } function setAttr (el, key, value) { - if (isBooleanAttr(key)) { + if (el.tagName.indexOf('-') > -1) { + baseSetAttr(el, key, value); + } else if (isBooleanAttr(key)) { // set attribute for blank value // e.g. if (isFalsyAttrValue(value)) { @@ -6259,35 +6357,39 @@ function setAttr (el, key, value) { el.setAttributeNS(xlinkNS, key, value); } } else { - if (isFalsyAttrValue(value)) { - el.removeAttribute(key); - } else { - // #7138: IE10 & 11 fires input event when setting placeholder on - //