diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..09f46ce8c4
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,3 @@
+Note
+====
+This repository is for Vue 1.x and 2.x only. Issues and pull requests related to 3.x are managed in the v3 doc repo: https://github.com/vuejs/docs-next.
diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index 988d5e9ef1..0000000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-v8.9.4
\ No newline at end of file
diff --git a/README.md b/README.md
index 1a418c2431..bed7c6049c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,13 @@
-# vuejs.org
+# v2.vuejs.org
+
+> Important: This repository is for Vue 1.x and 2.x only. Issues and pull requests related to 3.x are managed in the [v3 doc repo](https://github.com/vuejs/docs-next).
This site is built with [hexo](http://hexo.io/). Site content is written in Markdown format located in `src`. Pull requests welcome!
+## Writing
+
+See the [Vue Docs Writing Guide](https://github.com/vuejs/v2.vuejs.org/blob/master/writing-guide.md) for our rules and recommendations on writing and maintaining documentation.
+
## Developing
``` bash
@@ -81,9 +87,25 @@ Russian translation is maintained by Translation Gang.
### Spanish
-Spanish translation is maintained by [1950Labs](https://1950labs.com) and Vue.js Montevideo ([Leonel More](https://twitter.com/leonelmore), [Sebastian Camacho](https://twitter.com/sxcamacho), and [Diana Rodriguez](https://vue.beingadev.rocks).
-
* Translation Repo - [/1950Labs/vuejs.org](https://github.com/1950Labs/vuejs.org)
+* Spanish translation is maintained by:
+
+[1950Labs](https://1950labs.com) & [Vue.js Montevideo](https://www.meetup.com/Montevideo-Vue-JS-Meetup/):
+
+- [Leonel More](https://github.com/leonelmore) | [Twitter](https://twitter.com/leonelmore)
+- [Sebastián Camacho](https://github.com/sxcamacho) | [Twitter](https://twitter.com/sxcamacho)
+- [Diana Rodríguez](https://github.com/alphacentauri82) | [Twitter](https://twitter.com/cotufa82)
+- [Alejandro Parada](https://github.com/alejandro8605)
+- [José Javier Señaris](https://github.com/pepesenaris) | [Twitter](https://twitter.com/pepesenaris)
+- [Federico Kauffman](https://github.com/fedekau) | [Twitter](https://twitter.com/fedekauffman)
+- [Fabián Larrañaga](https://github.com/FLarra) | [Twitter](https://twitter.com/FLarraa)
+- [Pablo Marcano](https://github.com/Pablosky12) | [Twitter](https://twitter.com/stiv_ml)
+- [Nicolás Tinte](https://github.com/Tintef) | [Twitter](https://twitter.com/NicoTinte)
+- [Diego Barreiro](https://github.com/faliure)
+- [Matías Verdier](https://github.com/MatiasVerdier) | [Twitter](https://twitter.com/matiasvj)
+- [Pablo Kz](https://github.com/pabloKz)
+- [Leonardo Fagundez](https://github.com/lfgdzdev) | [Twitter](https://twitter.com/Lfgdz)
+
### Vietnamese
@@ -92,9 +114,15 @@ Vietnamese translation is maintained by [Vue.js Vietnam User group](https://gith
* Translation Repo: [/vuejs-vn/vuejs.org](https://github.com/vuejs-vn/vuejs.org)
* Primary maintainer - [phanan](https://github.com/phanan)
+### Bahasa Indonesia
+
+Bahasa Indonesia translation is maintained by [Vue.js Indonesia](https://github.com/vuejs-id/).
+
+* Translation Repo: [/vuejs-id/docs](https://github.com/vuejs-id/docs)
+
### Want to help with the translation?
-If you feel okay with translating quite alone, you can fork the repo, post a comment on the [Community Translation Announcements](https://github.com/vuejs/vuejs.org/issues/2015) issue page to inform others that you're doing the translation and go for it.
+If you feel okay with translating quite alone, you can fork the repo, post a comment on the [Community Translation Announcements](https://github.com/vuejs/v2.vuejs.org/issues/2015) issue page to inform others that you're doing the translation and go for it.
If you are more of a team player, Translation Gang might be for you. Let us know somehow that you're ready to join this international open-source translators community. Feel free to contact [Grigoriy Beziuk](https://gbezyuk.github.io) or anybody else from [the team](https://github.com/orgs/translation-gang/people).
diff --git a/_config.yml b/_config.yml
index a0ba1bd4c2..38ce868cd3 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1,6 +1,6 @@
# Hexo Configuration
-## Docs: http://zespia.tw/hexo/docs/configuration.html
-## Source: https://github.com/tommy351/hexo/
+## Docs: https://hexo.io/docs/
+## Source: https://github.com/hexojs/hexo
# Site
title: Vue.js
@@ -12,7 +12,7 @@ language:
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
-url: https://vuejs.org
+url: https://v2.vuejs.org
root: /
permalink: :year/:month/:day/:title/
tag_dir: tags
@@ -29,7 +29,8 @@ new_post_name: :title.md # File name of new posts
default_layout: post
auto_spacing: false # Add spaces between asian characters and western characters
titlecase: false # Transform title into titlecase
-external_link: true # Open external links in new tab
+external_link:
+ enable: true # Open external links in new tab
max_open_file: 100
multi_thread: true
filename_case: 0
@@ -77,9 +78,14 @@ pagination_dir: page
# Disqus
disqus_shortname:
+# Include/Exclude Files/Folders
+exclude:
+## Exclude example code from Nunjucks
+ - "v2/examples/vue-20-*/*"
+
# Extensions
-## Plugins: https://github.com/tommy351/hexo/wiki/Plugins
-## Themes: https://github.com/tommy351/hexo/wiki/Themes
+## Plugins: https://github.com/hexojs/hexo/wiki/Plugins
+## Themes: https://github.com/hexojs/hexo/wiki/Themes
theme: vue
exclude_generator:
@@ -97,49 +103,49 @@ markdown:
# Offline
## Config passed to sw-precache
## https://github.com/JLHwung/hexo-offline
-offline:
- maximumFileSizeToCacheInBytes: 10485760
- staticFileGlobs:
- - public/**/*.{js,html,css,png,jpg,jpeg,gif,svg,eot,ttf,woff,woff2,json,xml}
- stripPrefix: public
- verbose: true
- runtimeCaching:
- # Ad Sources - should be networkFirst
- - urlPattern: /*
- handler: networkFirst
- options:
- origin: sendgrid.sp1.convertro.com
- - urlPattern: /*
- handler: networkFirst
- options:
- origin: ad.doubleclick.net
- # CDNs - should be cacheFirst, since they should be used specific versions so should not change
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: cdn.jsdelivr.net
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: fonts.googleapis.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: fonts.gstatic.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: cdnjs.cloudflare.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: maxcdn.bootstrapcdn.com
+# offline:
+# maximumFileSizeToCacheInBytes: 10485760
+# staticFileGlobs:
+# - public/**/*.{js,html,css,png,jpg,jpeg,gif,svg,eot,ttf,woff,woff2,json,xml}
+# stripPrefix: public
+# verbose: true
+# runtimeCaching:
+# # Ad Sources - should be networkFirst
+# - urlPattern: /*
+# handler: networkFirst
+# options:
+# origin: sendgrid.sp1.convertro.com
+# - urlPattern: /*
+# handler: networkFirst
+# options:
+# origin: ad.doubleclick.net
+# # CDNs - should be cacheFirst, since they should be used specific versions so should not change
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: cdn.jsdelivr.net
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: fonts.googleapis.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: fonts.gstatic.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: cdnjs.cloudflare.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: maxcdn.bootstrapcdn.com
# Deployment
-## Docs: http://zespia.tw/hexo/docs/deployment.html
+## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
- repository: git@github.com:vuejs/vuejs.org.git
+ repository: git@github.com:vuejs/v2.vuejs.org.git
feed:
type: atom
diff --git a/_scripts/pre-deploy.js b/_scripts/pre-deploy.js
new file mode 100644
index 0000000000..bf435118ed
--- /dev/null
+++ b/_scripts/pre-deploy.js
@@ -0,0 +1,61 @@
+// udpate to latest built files of Vue
+require('./sync-sponsors')
+
+const fs = require('fs')
+const zlib = require('zlib')
+const axios = require('axios')
+const execSync = require('child_process').execSync
+
+const themeconfPath = 'themes/vue/_config.yml'
+const installPath = 'src/v2/guide/installation.md'
+const themeconfig = fs.readFileSync(themeconfPath, 'utf-8')
+const installation = fs.readFileSync(installPath, 'utf-8')
+
+// get latest Vue version
+console.log(`Checking latest Vue version...`)
+const localVersion = themeconfig.match(/vue_version: (.*)/)[1]
+const version = execSync('npm view vue@v2-latest version').toString().trim()
+
+if (localVersion === version) {
+ console.log(`Version is up-to-date.`)
+ process.exit(0)
+}
+
+console.log(`Latest version: ${version}. Downloading dist files...`)
+
+// replace version in theme config
+fs.writeFileSync(
+ themeconfPath,
+ themeconfig.replace(/vue_version: .*/, 'vue_version: ' + version)
+)
+
+// grab it from unpkg
+Promise.all([download(`vue.js`), download(`vue.min.js`)])
+ .then(([devSize, prodSize]) => {
+ // replace installation page version and size
+ fs.writeFileSync(
+ installPath,
+ installation
+ .replace(/vue_version: .*/, 'vue_version: ' + version)
+ .replace(/gz_size:.*/g, `gz_size: "${prodSize}"`)
+ .replace(/\/vue@[\d\.]+/g, `/vue@${version}`)
+ )
+ console.log(
+ `\nSuccessfully updated Vue version (${version}) and gzip file size (${prodSize}kb).\n`
+ )
+ })
+ .catch((err) => {
+ console.error(err)
+ process.exit(1)
+ })
+
+function download(file) {
+ return axios({
+ url: `http://unpkg.com/vue@${version}/dist/${file}`,
+ method: 'get'
+ }).then((res) => {
+ fs.writeFileSync(`themes/vue/source/js/${file}`, res.data)
+ const zipped = zlib.gzipSync(Buffer.from(res.data))
+ return (zipped.length / 1024).toFixed(2)
+ })
+}
diff --git a/_scripts/sync-sponsors.js b/_scripts/sync-sponsors.js
new file mode 100644
index 0000000000..60c726da62
--- /dev/null
+++ b/_scripts/sync-sponsors.js
@@ -0,0 +1,18 @@
+// sync latest data from sponsor.vuejs.org
+const fs = require('fs')
+const path = require('path')
+const axios = require('axios')
+const yaml = require('js-yaml')
+
+const configPath = path.resolve(__dirname, '../themes/vue/_config.yml')
+
+;(async () => {
+ const { data } = await axios(`https://sponsors.vuejs.org/data.json`)
+ const yml = yaml.dump(data)
+ const config = fs.readFileSync(configPath, 'utf-8')
+ const updated = config.replace(
+ /(# START SPONSORS)[^]*(# END SPONSORS)/,
+ `$1\n${yml}$2`
+ )
+ fs.writeFileSync(configPath, updated)
+})()
diff --git a/assets/why-vue/arabic.js.srt b/assets/why-vue/arabic.js.srt
index 0388f0dd2d..af61b3d07c 100644
--- a/assets/why-vue/arabic.js.srt
+++ b/assets/why-vue/arabic.js.srt
@@ -411,7 +411,7 @@ H2 إلى قائمة غير مرتبة،
94
00:03:57,460 --> 00:03:59,850
-دعنا نلغي العنصر الأخير من المصفوفة
+دعنا نلغي العنصر الأخير من المصفوفة
95
00:03:59,850 --> 00:04:01,828
diff --git a/package.json b/package.json
index 030bfdfb41..b88a44c727 100644
--- a/package.json
+++ b/package.json
@@ -1,32 +1,31 @@
{
- "name": "vuejs.org",
+ "name": "v2.vuejs.org",
"private": true,
"hexo": {
- "version": "3.8.0"
+ "version": "6.2.0"
},
"scripts": {
- "start": "hexo server",
- "build": "node pre-deploy.js && hexo clean && hexo generate",
+ "dev": "node _scripts/sync-sponsors.js && hexo server",
+ "build": "node _scripts/pre-deploy.js && hexo clean && hexo generate",
"deploy": "npm run build && hexo deploy"
},
"engines": {
- "node": ">=8.9.0"
+ "node": ">=14.0.0"
},
"dependencies": {
- "hexo": "^3.6.0",
- "hexo-deployer-git": "0.3.1",
+ "axios": "^0.27.2",
+ "hexo": "^6.2.0",
"hexo-generator-alias": "git+https://github.com/chrisvfritz/vuejs.org-hexo-generator-alias.git",
- "hexo-generator-archive": "^0.1.5",
- "hexo-generator-category": "^0.1.3",
- "hexo-generator-feed": "^1.2.2",
- "hexo-generator-index": "^0.2.1",
- "hexo-generator-tag": "^0.2.0",
- "hexo-offline": "^1.0.0",
- "hexo-renderer-ejs": "^0.3.1",
- "hexo-renderer-marked": "^0.3.0",
- "hexo-renderer-stylus": "^0.3.3",
- "hexo-server": "^0.3.1",
+ "hexo-generator-archive": "^1.0.0",
+ "hexo-generator-category": "^1.0.0",
+ "hexo-generator-feed": "^3.0.0",
+ "hexo-generator-index": "^2.0.0",
+ "hexo-generator-tag": "^1.0.0",
+ "hexo-renderer-ejs": "^2.0.0",
+ "hexo-renderer-marked": "^0.3.2",
+ "hexo-renderer-stylus": "^2.1.0",
+ "hexo-server": "^3.0.0",
"hoek": "^6.1.2",
- "request": "^2.85.0"
+ "js-yaml": "^4.1.0"
}
}
diff --git a/pre-deploy.js b/pre-deploy.js
deleted file mode 100644
index 1abac6b4fa..0000000000
--- a/pre-deploy.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// udpate to latest built files of Vue
-
-const fs = require('fs')
-const zlib = require('zlib')
-const request = require('request')
-const execSync = require('child_process').execSync
-
-const themeconfPath = 'themes/vue/_config.yml'
-const installPath = 'src/v2/guide/installation.md'
-const themeconfig = fs.readFileSync(themeconfPath, 'utf-8')
-const installation = fs.readFileSync(installPath, 'utf-8')
-
-// get latest Vue version
-console.log(`Checking latest Vue version...`)
-const localVersion = themeconfig.match(/vue_version: (.*)/)[1]
-const version = execSync('npm view vue version').toString().trim()
-
-if (localVersion === version) {
- console.log(`Version is up-to-date.`)
- process.exit(0)
-}
-
-console.log(`Latest version: ${version}. Downloading dist files...`)
-
-// replace version in theme config
-fs.writeFileSync(
- themeconfPath,
- themeconfig.replace(/vue_version: .*/, 'vue_version: ' + version)
-)
-
-// grab it from unpkg
-Promise.all([
- download(`vue.js`),
- download(`vue.min.js`)
-]).then(([ devSize, prodSize ]) => {
- // replace installation page version and size
- fs.writeFileSync(
- installPath,
- installation
- .replace(/vue_version: .*/, 'vue_version: ' + version)
- .replace(/gz_size:.*/g, `gz_size: "${prodSize}"`)
- .replace(/\/vue@[\d\.]+\//g, `/vue@${version}/`)
- )
- console.log(`\nSuccessfully updated Vue version and gzip file size.\n`)
-}).catch(err => {
- console.error(err)
- process.exit(1)
-})
-
-function download (file) {
- return new Promise((resolve, reject) => {
- request({
- url: `http://unpkg.com/vue@${version}/dist/${file}`,
- encoding: null
- }, (err, res, body) => {
- if (err) {
- return reject(err)
- }
- if (res.statusCode != 200) {
- return reject(
- `unexpected response code when downloading from unpkg: ${res.statusCode}` +
- `\n${body.toString()}`
- )
- }
- fs.writeFile(`themes/vue/source/js/${file}`, body, err => {
- if (err) return reject(err)
- zlib.gzip(body, (err, zipped) => {
- if (err) return reject(err)
- resolve((zipped.length / 1024).toFixed(2))
- })
- })
- })
- })
-}
diff --git a/src/_posts/common-gotchas.md b/src/_posts/common-gotchas.md
index a8abf2314e..c4ed741291 100644
--- a/src/_posts/common-gotchas.md
+++ b/src/_posts/common-gotchas.md
@@ -15,7 +15,7 @@ Most of the time, when you change a Vue instance's data, the view updates. But t
2. When you modify an Array by directly setting an index (e.g. `arr[0] = val`) or modifying its `length` property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method `arr.$set(index, value)` which is syntax sugar for `arr.splice(index, 1, value)`.
-Further reading: [Reactivity in Depth](/guide/reactivity.html) and [Array Change Detection](http://vuejs.org/guide/list.html#Array-Change-Detection).
+Further reading: [Reactivity in Depth](/guide/reactivity.html) and [Array Change Detection](/guide/list.html#Array-Change-Detection).
### When is the DOM updated?
@@ -33,6 +33,6 @@ Further reading: [Component Option Caveats](/guide/components.html#Component-Opt
All Vue.js templates are valid, parsable HTML markup, and Vue.js relies on spec-compliant parsers to process its templates. However, as specified in the standard, HTML is case-insensitive when matching tag and attribute names. This means camelCase attributes like `:myProp="123"` will be matched as `:myprop="123"`. As a rule of thumb, you should use camelCase in JavaScript and kebab-case in templates. For example a prop defined in JavaScript as `myProp` should be bound in templates as `:my-prop`.
-Further reading: [camelCase vs. kebab-case](http://vuejs.org/guide/components.html#camelCase-vs-kebab-case).
+Further reading: [camelCase vs. kebab-case](/guide/components.html#camelCase-vs-kebab-case).
We are also discussing the possibility of eliminating this inconsistency by resolving props and components in a case-insensitive manner. Join the conversation [here](https://github.com/vuejs/vue/issues/2308).
diff --git a/src/_posts/why-no-template-url.md b/src/_posts/why-no-template-url.md
index f6fbabe2dd..8ffacabbbb 100644
--- a/src/_posts/why-no-template-url.md
+++ b/src/_posts/why-no-template-url.md
@@ -13,8 +13,8 @@ First, it allows us to write our template in a separate HTML file. This gives us
Second, because `templateURL` loads the template via Ajax at runtime, you don't need a build step in order to split up your files. This is convenient during development, but comes at a serious cost when you want to deploy it to production. Before HTTP/2 is universally supported, the number of HTTP requests is still probably the most critical factor in your app's initial load performance. Now imagine you use `templateURL` for every component in your app - the browser needs to perform dozens of HTTP requests before even being able to display anything! In case you don't know, most browsers limit the number of parallel requests it can perform to a single server. When you exceed that limit, your app's initial rendering will suffer for every extra round trip the browser has to wait for. Sure, there are build tools that can help you pre-register all those templates in `$templateCache` - but that shows us a build step is, in fact, inevitable for any serious frontend development.
-So, without `templateURL`, how do we deal with the development experience problem? Writing templates as inline JavaScript strings is terrible, faking templates with `
+
+
+{% endraw %}
diff --git a/src/support-vuejs/index.md b/src/support-vuejs/index.md
index e010c9081d..679571bc4c 100644
--- a/src/support-vuejs/index.md
+++ b/src/support-vuejs/index.md
@@ -1,3 +1,4 @@
---
sponsors: true
+type: sponsors
---
diff --git a/src/v2/api/index.md b/src/v2/api/index.md
index ad585ce963..2e073bbcb6 100644
--- a/src/v2/api/index.md
+++ b/src/v2/api/index.md
@@ -684,6 +684,7 @@ type: api
handler: 'someMethod',
immediate: true
},
+ // you can pass array of callbacks, they will be called one-by-one
e: [
'handle1',
function handle2 (val, oldVal) { /* ... */ },
@@ -942,7 +943,7 @@ type: api
- **Details:**
- Called when an error from any descendent component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can return `false` to stop the error from propagating further.
+ Called when an error from any descendant component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can return `false` to stop the error from propagating further.
You can modify component state in this hook. However, it is important to have conditionals in your template or render function that short circuits other content when an error has been captured; otherwise the component will be thrown into an infinite render loop.
@@ -1058,8 +1059,6 @@ type: api
- **Details:**
- `provide` and `inject` are primarily provided for advanced plugin / component library use cases. It is NOT recommended to use them in generic application code.
-
This pair of options are used together to allow an ancestor component to serve as a dependency injector for all its descendants, regardless of how deep the component hierarchy is, as long as they are in the same parent chain. If you are familiar with React, this is very similar to React's context feature.
The `provide` option should be an object or a function that returns an object. This object contains the properties that are available for injection into its descendants. You can use ES2015 Symbols as keys in this object, but only in environments that natively support `Symbol` and `Reflect.ownKeys`.
@@ -1383,10 +1382,14 @@ type: api
- **Read only**
+- **Reactive?** No
+
- **Details:**
Used to programmatically access content [distributed by slots](../guide/components.html#Content-Distribution-with-Slots). Each [named slot](../guide/components.html#Named-Slots) has its own corresponding property (e.g. the contents of `v-slot:foo` will be found at `vm.$slots.foo`). The `default` property contains either nodes not included in a named slot or contents of `v-slot:default`.
+ Please note that slots are **not** reactive. If you need a component to re-render based on changes to data passed to a slot, we suggest considering a different strategy that relies on a reactive instance option, such as `props` or `data`.
+
**Note:** `v-slot:foo` is supported in v2.6+. For older versions, you can use the [deprecated syntax](../guide/components-slots.html#Deprecated-Syntax).
Accessing `vm.$slots` is most useful when writing a component with a [render function](../guide/render-function.html).
@@ -1534,7 +1537,7 @@ type: api
// function
vm.$watch(
function () {
- // everytime the expression `this.a + this.b` yields a different result,
+ // every time the expression `this.a + this.b` yields a different result,
// the handler will be called. It's as if we were watching a computed
// property without defining the computed property itself
return this.a + this.b
@@ -1576,6 +1579,35 @@ type: api
// `callback` is fired immediately with current value of `a`
```
+ Note that with `immediate` option you won't be able to unwatch the given property on the first callback call.
+
+ ``` js
+ // This will cause an error
+ var unwatch = vm.$watch(
+ 'value',
+ function () {
+ doSomething()
+ unwatch()
+ },
+ { immediate: true }
+ )
+ ```
+
+ If you still want to call an unwatch function inside the callback, you should check its availability first:
+
+ ``` js
+ var unwatch = vm.$watch(
+ 'value',
+ function () {
+ doSomething()
+ if (unwatch) {
+ unwatch()
+ }
+ },
+ { immediate: true }
+ )
+ ```
+
### vm.$set( target, propertyName/index, value )
- **Arguments:**
@@ -2168,7 +2200,7 @@ type: api
-
+
@@ -2349,7 +2381,7 @@ type: api
### key
-- **Expects:** `number | string`
+- **Expects:** `number | string | boolean (since 2.4.2) | symbol (since 2.5.12)`
The `key` special attribute is primarily used as a hint for Vue's virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list. Without keys, Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible. With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed/destroyed.
@@ -2564,7 +2596,7 @@ Used to denote a `
` element as a scoped slot.
`` serve as transition effects for **multiple** elements/components. The `` renders a real DOM element. By default it renders a ``, and you can configure what element it should render via the `tag` attribute.
- Note every child in a `` must be **uniquely keyed** for the animations to work properly.
+ Note that every child in a `` must be **uniquely keyed** for the animations to work properly.
`` supports moving transitions via CSS transform. When a child's position on screen has changed after an update, it will get applied a moving CSS class (auto generated from the `name` attribute or configured with the `move-class` attribute). If the CSS `transform` property is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the [FLIP technique](https://aerotwist.com/blog/flip-your-animations/).
diff --git a/src/v2/cookbook/adding-instance-properties.md b/src/v2/cookbook/adding-instance-properties.md
index 5e18247356..8df1c7eab0 100644
--- a/src/v2/cookbook/adding-instance-properties.md
+++ b/src/v2/cookbook/adding-instance-properties.md
@@ -6,7 +6,7 @@ order: 2
## Base Example
-There may be data/utilities you'd like to use in many components, but you don't want to [pollute the global scope](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md). In these cases, you can make them available to each Vue instance by defining them on the prototype:
+There may be data/utilities you'd like to use in many components, but you don't want to [pollute the global scope](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch3.md). In these cases, you can make them available to each Vue instance by defining them on the prototype:
```js
Vue.prototype.$appName = 'My App'
@@ -58,7 +58,7 @@ new Vue({
})
```
-It would be `"My App"`, then `"The name of some other app"`, because `this.appName` is overwritten ([sort of](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md)) by `data` when the instance is created. We scope instance properties with `$` to avoid this. You can even use your own convention if you'd like, such as `$_appName` or `ΩappName`, to prevent even conflicts with plugins or future features.
+It would be `"My App"`, then `"The name of some other app"`, because `this.appName` is overwritten ([sort of](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20%26%20object%20prototypes/ch5.md)) by `data` when the instance is created. We scope instance properties with `$` to avoid this. You can even use your own convention if you'd like, such as `$_appName` or `ΩappName`, to prevent even conflicts with plugins or future features.
## Real-World Example: Replacing Vue Resource with Axios
diff --git a/src/v2/cookbook/client-side-storage.md b/src/v2/cookbook/client-side-storage.md
index b40f2a633d..915ff798bf 100644
--- a/src/v2/cookbook/client-side-storage.md
+++ b/src/v2/cookbook/client-side-storage.md
@@ -170,7 +170,7 @@ const app = new Vue({
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:
+We have three methods now to handle working with cats. 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 .
diff --git a/src/v2/cookbook/creating-custom-scroll-directives.md b/src/v2/cookbook/creating-custom-scroll-directives.md
index 3d6ea76b84..645ba3eb5c 100644
--- a/src/v2/cookbook/creating-custom-scroll-directives.md
+++ b/src/v2/cookbook/creating-custom-scroll-directives.md
@@ -6,7 +6,7 @@ order: 7
## Base Example
-There are many times that we might want to add a bit of behavior, especially animation, to a scroll event on a site. There are many ways to do so, but the path with the least amount of code and dependencies is perhaps to use a [custom directive](https://vuejs.org/v2/guide/custom-directive.html) to create a hook for anything that fires off a particular scroll event.
+There are many times that we might want to add a bit of behavior, especially animation, to a scroll event on a site. There are many ways to do so, but the path with the least amount of code and dependencies is perhaps to use a [custom directive](/v2/guide/custom-directive.html) to create a hook for anything that fires off a particular scroll event.
```js
Vue.directive('scroll', {
diff --git a/src/v2/cookbook/debugging-in-vscode.md b/src/v2/cookbook/debugging-in-vscode.md
index 9fbf8140c7..5c79d7b6dd 100644
--- a/src/v2/cookbook/debugging-in-vscode.md
+++ b/src/v2/cookbook/debugging-in-vscode.md
@@ -59,7 +59,7 @@ Click on the Debugging icon in the Activity Bar to bring up the Debug view, then
"webRoot": "${workspaceFolder}/src",
"breakOnLoad": true,
"sourceMapPathOverrides": {
- "webpack:///./src/*": "${webRoot}/*"
+ "webpack:///src/*": "${webRoot}/*"
}
},
{
diff --git a/src/v2/cookbook/dockerize-vuejs-app.md b/src/v2/cookbook/dockerize-vuejs-app.md
index 12b282dd32..1fc4ed6299 100644
--- a/src/v2/cookbook/dockerize-vuejs-app.md
+++ b/src/v2/cookbook/dockerize-vuejs-app.md
@@ -35,7 +35,7 @@ EXPOSE 8080
CMD [ "http-server", "dist" ]
```
-It may seem reduntant to first copy `package.json` and `package-lock.json` and then all project files and folders in two separate steps but there is actually [a very good reason for that](http://bitjudo.com/blog/2014/03/13/building-efficient-dockerfiles-node-dot-js/) (spoiler: it allows us to take advantage of cached Docker layers).
+It may seem redundant to first copy `package.json` and `package-lock.json` and then all project files and folders in two separate steps but there is actually [a very good reason for that](http://bitjudo.com/blog/2014/03/13/building-efficient-dockerfiles-node-dot-js/) (spoiler: it allows us to take advantage of cached Docker layers).
Now let's build the Docker image of our Vue.js app:
@@ -121,7 +121,7 @@ So, delivering our Vue.js app as a Docker image helps reducing, if not removing
### Effects of Continuous Delivery
-By leveraging the [Continuous Delivery](https://martinfowler.com/bliki/ContinuousDelivery.html) discipline we build our software in a way that it can potentially be released to production at any time. Such engineering practice is enabled by means of what is normally called [continuous delivery pipeline](https://martinfowler.com/bliki/DeploymentPipeline.html). The purpose of a continuous delivery pipeline is to split our build into stages (e.g. compilation, unit tests, integration tests, performance tests, etc.) and let each stage verify our build artifact whenever our software changes. Ultimately, each stage increases our confidence in the production readiness of our build artifact and, therefore, reduces the risk of breaking things in production (or any other environment for that matters).
+By leveraging the [Continuous Delivery](https://martinfowler.com/bliki/ContinuousDelivery.html) discipline we build our software in a way that it can potentially be released to production at any time. Such engineering practice is enabled by means of what is normally called [continuous delivery pipeline](https://martinfowler.com/bliki/DeploymentPipeline.html). The purpose of a continuous delivery pipeline is to split our build into stages (e.g. compilation, unit tests, integration tests, performance tests, etc.) and let each stage verify our build artifact whenever our software changes. Ultimately, each stage increases our confidence in the production readiness of our build artifact and, therefore, reduces the risk of breaking things in production (or any other environment for that matter).
So, creating a Docker image for our Vue.js app is a good choice here because that would represent our final build artifact, the same artifact that would be verified against our continuous delivery pipeline and that could potentially be released to production with confidence.
diff --git a/src/v2/cookbook/editable-svg-icons.md b/src/v2/cookbook/editable-svg-icons.md
index 003b127bbd..a1903f5533 100644
--- a/src/v2/cookbook/editable-svg-icons.md
+++ b/src/v2/cookbook/editable-svg-icons.md
@@ -175,7 +175,7 @@ Designers may change their minds. Product requirements change. Keeping the logic
## When To Avoid This Pattern
-This type of SVG icon system is really useful when you have a number of icons that are used in different ways throughout your site. If you're repeating the same icon many times on one page (e.g. a giant table a delete icon in each row), it might make more sense to have all of the sprites compiled into a sprite sheet and use `` tags to load them.
+This type of SVG icon system is really useful when you have a number of icons that are used in different ways throughout your site. If you're repeating the same icon many times on one page (e.g. a giant table with a delete icon in each row), it might make more sense to have all of the sprites compiled into a sprite sheet and use `` tags to load them.
## Alternative Patterns
diff --git a/src/v2/cookbook/form-validation.md b/src/v2/cookbook/form-validation.md
index f21e2ae8b8..0325ce601d 100644
--- a/src/v2/cookbook/form-validation.md
+++ b/src/v2/cookbook/form-validation.md
@@ -1,433 +1,440 @@
----
-title: Form Validation
-type: cookbook
-order: 3
----
-
-## Base Example
-
-Form validation is natively supported by the browser, but sometimes different browsers will handle things in a manner which makes relying on it a bit tricky. Even when validation is supported perfectly, there may be times when custom validations are needed and a more manual, Vue-based solution may be more appropriate. Let's begin with a simple example.
-
-Given a form of three fields, make two required. Let's look at the HTML first:
-
-``` html
-
-```
-
-Let's cover it from the top. The `
-```
-
-While the change here is small, note the `novalidate="true"` on top. This is important because the browser will attempt to validate the email address in the field when `type="email"`. Frankly it may make more sense to trust the browser in this case, but as we wanted an example with custom validation, we're disabling it. Here's the updated JavaScript.
-
-``` js
-const app = new Vue({
- el: '#app',
- data: {
- errors: [],
- name: null,
- email: null,
- movie: null
- },
- methods: {
- checkForm: function (e) {
- this.errors = [];
-
- if (!this.name) {
- this.errors.push("Name required.");
- }
- if (!this.email) {
- this.errors.push('Email required.');
- } else if (!this.validEmail(this.email)) {
- this.errors.push('Valid email required.');
- }
-
- if (!this.errors.length) {
- return true;
- }
-
- e.preventDefault();
- },
- validEmail: function (email) {
- var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(email);
- }
- }
-})
-```
-
-As you can see, we've added `validEmail` as a new method and it is simply called from `checkForm`. You can play with this example here:
-
-See the Pen form validation 2 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Another Example of Custom Validation
-
-For the third example, we've built something you've probably seen in survey apps. The user is asked to spend a "budget" for a set of features for a new Star Destroyer model. The total must equal 100. First, the HTML.
-
-``` html
-
-```
-
-Note the set of inputs covering the five different features. Note the addition of `.number` to the `v-model` attribute. This tells Vue to cast the value to a number when you use it. However, there is a bug with this feature such that when the value is blank, it turns back into a string. You'll see the workaround below. To make it a bit easier for the user, we also added a current total right below so they can see, in real time, what their total is. Now let's look at the JavaScript.
-
-``` js
-const app = new Vue({
- el: '#app',
- data:{
- errors: [],
- weapons: 0,
- shields: 0,
- coffee: 0,
- ac: 0,
- mousedroids: 0
- },
- computed: {
- total: function () {
- // must parse because Vue turns empty value to string
- return Number(this.weapons) +
- Number(this.shields) +
- Number(this.coffee) +
- Number(this.ac+this.mousedroids);
- }
- },
- methods:{
- checkForm: function (e) {
- this.errors = [];
-
- if (this.total != 100) {
- this.errors.push('Total must be 100!');
- }
-
- if (!this.errors.length) {
- return true;
- }
-
- e.preventDefault();
- }
- }
-})
-```
-
-We set up the total value as a computed value, and outside of that bug I ran into, it was simple enough to setup. My checkForm method now just needs to see if the total is 100 and that's it. You can play with this here:
-
-See the Pen form validation 3 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Server-side Validation
-
-In my final example, we built something that makes use of Ajax to validate at the server. The form will ask you to name a new product and will then check to ensure that the name is unique. We wrote a quick [OpenWhisk](http://openwhisk.apache.org/) serverless action to do the validation. While it isn't terribly important, here is the logic:
-
-``` js
-function main(args) {
- return new Promise((resolve, reject) => {
- // bad product names: vista, empire, mbp
- const badNames = ['vista', 'empire', 'mbp'];
-
- if (badNames.includes(args.name)) {
- reject({error: 'Existing product'});
- }
-
- resolve({status: 'ok'});
- });
-}
-```
-
-Basically any name but "vista", "empire", and "mbp" are acceptable. Ok, so let's look at the form.
-
-``` html
-
-```
-
-There isn't anything special here. So let's go on to the JavaScript.
-
-``` js
-const apiUrl = 'https://openwhisk.ng.bluemix.net/api/v1/web/rcamden%40us.ibm.com_My%20Space/safeToDelete/productName.json?name=';
-
-const app = new Vue({
- el: '#app',
- data: {
- errors: [],
- name: ''
- },
- methods:{
- checkForm: function (e) {
- e.preventDefault();
-
- this.errors = [];
-
- if (this.name === '') {
- this.errors.push('Product name is required.');
- } else {
- fetch(apiUrl + encodeURIComponent(this.name))
- .then(res => res.json())
- .then(res => {
- if (res.error) {
- this.errors.push(res.error);
- } else {
- // redirect to a new URL, or do something on success
- alert('ok!');
- }
- });
- }
- }
- }
-})
-```
-
-We start off with a variable representing the URL of the API that is running on OpenWhisk. Now look at `checkForm`. In this version, we always prevent the form from submitting (which, by the way, could be done in the HTML with Vue as well). You can see a basic check on `this.name` being empty, and then we hit the API. If it's bad, we add an error as before. If it's good, right now we do nothing (just an alert), but you could navigate the user to a new page with the product name in the URL, or do other actions as well. You can run this demo below:
-
-See the Pen form validation 4 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Alternative Patterns
-
-While this cookbook entry focused on doing form validation "by hand", there are, of course, some great Vue libraries that will handle a lot of this for you. Switching to a prepackage library may impact the final size of your application, but the benefits could be tremendous. You have code that is (most likely) heavily tested and also updated on a regular basis. Some examples of form validation libraries for Vue include:
-
-* [vuelidate](https://github.com/monterail/vuelidate)
-* [VeeValidate](http://vee-validate.logaretm.com/)
+---
+title: Form Validation
+type: cookbook
+order: 3
+---
+
+## Base Example
+
+
+
+Form validation is natively supported by the browser, but sometimes different browsers will handle things in a manner which makes relying on it a bit tricky. Even when validation is supported perfectly, there may be times when custom validations are needed and a more manual, Vue-based solution may be more appropriate. Let's begin with a simple example.
+
+Given a form of three fields, make two required. Let's look at the HTML first:
+
+``` html
+
+```
+
+Let's cover it from the top. The `
+```
+
+While the change here is small, note the `novalidate="true"` on top. This is important because the browser will attempt to validate the email address in the field when `type="email"`. Frankly it may make more sense to trust the browser in this case, but as we wanted an example with custom validation, we're disabling it. Here's the updated JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data: {
+ errors: [],
+ name: null,
+ email: null,
+ movie: null
+ },
+ methods: {
+ checkForm: function (e) {
+ this.errors = [];
+
+ if (!this.name) {
+ this.errors.push("Name required.");
+ }
+ if (!this.email) {
+ this.errors.push('Email required.');
+ } else if (!this.validEmail(this.email)) {
+ this.errors.push('Valid email required.');
+ }
+
+ if (!this.errors.length) {
+ return true;
+ }
+
+ e.preventDefault();
+ },
+ validEmail: function (email) {
+ var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ return re.test(email);
+ }
+ }
+})
+```
+
+As you can see, we've added `validEmail` as a new method and it is simply called from `checkForm`. You can play with this example here:
+
+See the Pen form validation 2 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Another Example of Custom Validation
+
+For the third example, we've built something you've probably seen in survey apps. The user is asked to spend a "budget" for a set of features for a new Star Destroyer model. The total must equal 100. First, the HTML.
+
+``` html
+
+```
+
+Note the set of inputs covering the five different features. Note the addition of `.number` to the `v-model` attribute. This tells Vue to cast the value to a number when you use it. However, there is a bug with this feature such that when the value is blank, it turns back into a string. You'll see the workaround below. To make it a bit easier for the user, we also added a current total right below so they can see, in real time, what their total is. Now let's look at the JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data:{
+ errors: [],
+ weapons: 0,
+ shields: 0,
+ coffee: 0,
+ ac: 0,
+ mousedroids: 0
+ },
+ computed: {
+ total: function () {
+ // must parse because Vue turns empty value to string
+ return Number(this.weapons) +
+ Number(this.shields) +
+ Number(this.coffee) +
+ Number(this.ac+this.mousedroids);
+ }
+ },
+ methods:{
+ checkForm: function (e) {
+ this.errors = [];
+
+ if (this.total != 100) {
+ this.errors.push('Total must be 100!');
+ }
+
+ if (!this.errors.length) {
+ return true;
+ }
+
+ e.preventDefault();
+ }
+ }
+})
+```
+
+We set up the total value as a computed value, and outside of that bug I ran into, it was simple enough to setup. My checkForm method now just needs to see if the total is 100 and that's it. You can play with this here:
+
+See the Pen form validation 3 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Server-side Validation
+
+In my final example, we built something that makes use of Ajax to validate at the server. The form will ask you to name a new product and will then check to ensure that the name is unique. We wrote a quick [Netlify](https://netlify.com/) serverless action to do the validation. While it isn't terribly important, here is the logic:
+
+``` js
+exports.handler = async (event, context) => {
+
+ const badNames = ['vista', 'empire', 'mbp'];
+ const name = event.queryStringParameters.name;
+
+ if (badNames.includes(name)) {
+ return {
+ statusCode: 400,
+ body: JSON.stringify({error: 'Invalid name passed.'})
+ }
+ }
+
+ return {
+ statusCode: 204
+ }
+
+}
+
+```
+
+Basically any name but "vista", "empire", and "mbp" are acceptable. Ok, so let's look at the form.
+
+``` html
+
+```
+
+There isn't anything special here. So let's go on to the JavaScript.
+
+``` js
+const apiUrl = 'https://vuecookbook.netlify.app/.netlify/functions/product-name?name=';
+
+const app = new Vue({
+ el: '#app',
+ data: {
+ errors: [],
+ name: ''
+ },
+ methods:{
+ checkForm: function (e) {
+ e.preventDefault();
+
+ this.errors = [];
+
+ if (this.name === '') {
+ this.errors.push('Product name is required.');
+ } else {
+ fetch(apiUrl + encodeURIComponent(this.name))
+ .then(async res => {
+ if (res.status === 204) {
+ alert('OK');
+ } else if (res.status === 400) {
+ let errorResponse = await res.json();
+ this.errors.push(errorResponse.error);
+ }
+ });
+ }
+ }
+ }
+})
+```
+
+We start off with a variable representing the URL of the API that is running on OpenWhisk. Now look at `checkForm`. In this version, we always prevent the form from submitting (which, by the way, could be done in the HTML with Vue as well). You can see a basic check on `this.name` being empty, and then we hit the API. If it's bad, we add an error as before. If it's good, right now we do nothing (just an alert), but you could navigate the user to a new page with the product name in the URL, or do other actions as well. You can run this demo below:
+
+See the Pen form validation 4 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Alternative Patterns
+
+While this cookbook entry focused on doing form validation "by hand", there are, of course, some great Vue libraries that will handle a lot of this for you. Switching to a prepackage library may impact the final size of your application, but the benefits could be tremendous. You have code that is (most likely) heavily tested and also updated on a regular basis. Some examples of form validation libraries for Vue include:
+
+* [vuelidate](https://github.com/monterail/vuelidate)
+* [VeeValidate](https://vee-validate.logaretm.com/v3/)
diff --git a/src/v2/cookbook/packaging-sfc-for-npm.md b/src/v2/cookbook/packaging-sfc-for-npm.md
index 61e6f4790d..fd7c9ce485 100644
--- a/src/v2/cookbook/packaging-sfc-for-npm.md
+++ b/src/v2/cookbook/packaging-sfc-for-npm.md
@@ -24,7 +24,7 @@ export default {
Or even used via `
+
...
@@ -39,7 +39,7 @@ Vue already allows components to be written as a single file. Because a Single F
> "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 `
-{% endraw %}
diff --git a/src/v2/examples/todomvc.md b/src/v2/examples/todomvc.md
index b3eee18d9a..362cf841c1 100644
--- a/src/v2/examples/todomvc.md
+++ b/src/v2/examples/todomvc.md
@@ -6,6 +6,6 @@ order: 11
> This is a fully spec-compliant TodoMVC implementation in under 120 effective lines of JavaScript (excluding comments and blank lines).
-Note that if your web browser is configured to block 3rd-party data/cookies, the example below will not work, as the `localStorage` data will fail to be saved from JSFiddle. You'll have to click on `Edit in JSFiddle` to see the live result.
+Note that if your web browser is configured to block 3rd-party data/cookies, the example below will not work, as the `localStorage` data will fail to be saved. You'll have to click on `Open Sandbox` to see the live result.
-
+
diff --git a/src/v2/examples/tree-view.md b/src/v2/examples/tree-view.md
index f0d34bfe8d..4922224947 100644
--- a/src/v2/examples/tree-view.md
+++ b/src/v2/examples/tree-view.md
@@ -6,4 +6,4 @@ order: 4
> Example of a simple tree view implementation showcasing recursive usage of components.
-
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html b/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html
new file mode 100644
index 0000000000..caf5244f40
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html
@@ -0,0 +1,88 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json b/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json
new file mode 100644
index 0000000000..3dcc5dba3f
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter-v2",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js b/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js
new file mode 100644
index 0000000000..80ab295e34
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js
@@ -0,0 +1,61 @@
+var currencyValidator = {
+ format: function(number) {
+ return (Math.trunc(number * 100) / 100).toFixed(2);
+ },
+ parse: function(newString, oldNumber) {
+ var CleanParse = function(value) {
+ return { value: value };
+ };
+ var CurrencyWarning = function(warning, value) {
+ return {
+ warning: warning,
+ value: value,
+ attempt: newString
+ };
+ };
+ var NotAValidDollarAmountWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " is not a valid dollar amount",
+ value
+ );
+ };
+ var AutomaticConversionWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " was automatically converted to " + value,
+ value
+ );
+ };
+
+ var newNumber = Number(newString);
+ var indexOfDot = newString.indexOf(".");
+ var indexOfE = newString.indexOf("e");
+
+ if (isNaN(newNumber)) {
+ if (
+ indexOfDot === -1 &&
+ indexOfE > 0 &&
+ indexOfE === newString.length - 1 &&
+ Number(newString.slice(0, indexOfE)) !== 0
+ ) {
+ return new CleanParse(oldNumber);
+ } else {
+ return new NotAValidDollarAmountWarning(oldNumber);
+ }
+ }
+
+ var newCurrencyString = currencyValidator.format(newNumber);
+ var newCurrencyNumber = Number(newCurrencyString);
+
+ if (newCurrencyNumber === newNumber) {
+ if (indexOfE !== -1 && indexOfE === newString.length - 2) {
+ return new AutomaticConversionWarning(newNumber);
+ } else {
+ return new CleanParse(newNumber);
+ }
+ } else {
+ return new NotAValidDollarAmountWarning(
+ newNumber > newCurrencyNumber ? newCurrencyNumber : oldNumber
+ );
+ }
+ }
+};
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html b/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html
new file mode 100644
index 0000000000..40d6041b2a
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json b/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json
new file mode 100644
index 0000000000..082e912c93
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter-v3",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/index.html b/src/v2/examples/vue-10-two-way-currency-filter/index.html
new file mode 100644
index 0000000000..e63f64f86b
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/index.html
@@ -0,0 +1,56 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/package.json b/src/v2/examples/vue-10-two-way-currency-filter/package.json
new file mode 100644
index 0000000000..ee92d5f0a8
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/index.html b/src/v2/examples/vue-20-accessing-parent-component-instance/index.html
new file mode 100644
index 0000000000..44606424db
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/index.html
@@ -0,0 +1,91 @@
+
+
+
+ Dependency Injection Google Maps Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/package.json b/src/v2/examples/vue-20-accessing-parent-component-instance/package.json
new file mode 100644
index 0000000000..f01eaa982e
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-accessing-parent-component-instance",
+ "version": "1.0.0",
+ "description": "Vue.js example accessing Parent Component Instance using Google Maps.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json b/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-component-blog-post-example/index.html b/src/v2/examples/vue-20-component-blog-post-example/index.html
new file mode 100644
index 0000000000..5682f7ef64
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/index.html
@@ -0,0 +1,43 @@
+
+
+
+ Component Blog Post Example
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-component-blog-post-example/package.json b/src/v2/examples/vue-20-component-blog-post-example/package.json
new file mode 100644
index 0000000000..65197ee445
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-component-blog-post-example",
+ "version": "1.0.0",
+ "description": "Dynamically passing props, like when fetching posts from an API.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json b/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dependency-injection/index.html b/src/v2/examples/vue-20-dependency-injection/index.html
new file mode 100644
index 0000000000..78f72a66f0
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Dependency Injection Google Maps Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dependency-injection/package.json b/src/v2/examples/vue-20-dependency-injection/package.json
new file mode 100644
index 0000000000..a4a7d58da3
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dependency-injection",
+ "version": "1.0.0",
+ "description": "Vue.js Dependency Injection example using Google Maps.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dependency-injection/sandbox.config.json b/src/v2/examples/vue-20-dependency-injection/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/index.html b/src/v2/examples/vue-20-dynamic-components-with-binding/index.html
new file mode 100644
index 0000000000..57ba72a4b0
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/index.html
@@ -0,0 +1,74 @@
+
+
+
+ Dynamic Components Example
+
+
+
+
+
+
+ {{ tab.name }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/package.json b/src/v2/examples/vue-20-dynamic-components-with-binding/package.json
new file mode 100644
index 0000000000..fdff914b68
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-components-with-binding",
+ "version": "1.0.0",
+ "description": "Showing binding to a component's options object.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json b/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-components/index.html b/src/v2/examples/vue-20-dynamic-components/index.html
new file mode 100644
index 0000000000..6d627b7ccb
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/index.html
@@ -0,0 +1,68 @@
+
+
+
+ Dynamic Components Example
+
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-components/package.json b/src/v2/examples/vue-20-dynamic-components/package.json
new file mode 100644
index 0000000000..67cb7f7c07
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-components",
+ "version": "1.0.0",
+ "description": "Used to dynamically switch between components, like in a tabbed interface.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-components/sandbox.config.json b/src/v2/examples/vue-20-dynamic-components/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/index.html b/src/v2/examples/vue-20-dynamic-state-transitions/index.html
new file mode 100644
index 0000000000..ff026bb789
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/index.html
@@ -0,0 +1,129 @@
+
+
+
+ Dynamic State Transitions
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/package.json b/src/v2/examples/vue-20-dynamic-state-transitions/package.json
new file mode 100644
index 0000000000..6880b42447
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-state-transitions",
+ "version": "1.0.0",
+ "description": "Data backing state transitions can be updated in real time, like in this example.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json b/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-elastic-header/index.html b/src/v2/examples/vue-20-elastic-header/index.html
new file mode 100644
index 0000000000..b14e193495
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/index.html
@@ -0,0 +1,115 @@
+
+
+
+ Elastic Header
+
+
+
+
+
+
+
+
+
+
+ Elastic Draggable SVG Header
+
+ with Vue.js +
+ dynamics.js
+
+
+
+
+ Note this is just an effect demo - there are of course many
+ additional details if you want to use this in production, e.g.
+ handling responsive sizes, reload threshold and content scrolling.
+ Those are out of scope for this quick little hack. However, the idea
+ is that you can hide them as internal details of a Vue.js component
+ and expose a simple Web-Component-like interface.
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-elastic-header/package.json b/src/v2/examples/vue-20-elastic-header/package.json
new file mode 100644
index 0000000000..6362227733
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-elastic-header",
+ "version": "1.0.0",
+ "description": "Elastic Draggable SVG Header",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-elastic-header/sandbox.config.json b/src/v2/examples/vue-20-elastic-header/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-elastic-header/style.css b/src/v2/examples/vue-20-elastic-header/style.css
new file mode 100644
index 0000000000..f3fc3f0b5c
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/style.css
@@ -0,0 +1,45 @@
+h1 {
+ font-weight: 300;
+ font-size: 1.8em;
+ margin-top: 0;
+}
+a {
+ color: #fff;
+}
+.draggable-header-view {
+ background-color: #fff;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
+ width: 320px;
+ height: 560px;
+ overflow: hidden;
+ margin: 30px auto;
+ position: relative;
+ font-family: "Roboto", Helvetica, Arial, sans-serif;
+ color: #fff;
+ font-size: 14px;
+ font-weight: 300;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.draggable-header-view .bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 0;
+}
+.draggable-header-view .header,
+.draggable-header-view .content {
+ position: relative;
+ z-index: 1;
+ padding: 30px;
+ box-sizing: border-box;
+}
+.draggable-header-view .header {
+ height: 160px;
+}
+.draggable-header-view .content {
+ color: #333;
+ line-height: 1.5em;
+}
diff --git a/src/v2/examples/vue-20-firebase-validation/index.html b/src/v2/examples/vue-20-firebase-validation/index.html
new file mode 100644
index 0000000000..dcdcd7af02
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/index.html
@@ -0,0 +1,96 @@
+
+
+
+ Firebase + Validation
+
+
+
+
+
+
+
+
+
+
+ {{user.name}} - {{user.email}}
+ X
+
+
+
+
+ Name cannot be empty.
+
+ Please provide a valid email address.
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-firebase-validation/package.json b/src/v2/examples/vue-20-firebase-validation/package.json
new file mode 100644
index 0000000000..570fb291d7
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-firebase-validation",
+ "version": "1.0.0",
+ "description": "This example uses Firebase as the data persistence backend and syncs between clients in real time (you can try opening it in multiple browser tabs). In addition, it performs instant validation using computed properties and triggers CSS transitions when adding/removing items.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-firebase-validation/sandbox.config.json b/src/v2/examples/vue-20-firebase-validation/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-firebase-validation/style.css b/src/v2/examples/vue-20-firebase-validation/style.css
new file mode 100644
index 0000000000..761054c0c1
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/style.css
@@ -0,0 +1,33 @@
+body {
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+ul {
+ padding: 0;
+}
+
+.user {
+ height: 30px;
+ line-height: 30px;
+ padding: 10px;
+ border-top: 1px solid #eee;
+ overflow: hidden;
+ transition: all 0.25s ease;
+}
+
+.user:last-child {
+ border-bottom: 1px solid #eee;
+}
+
+.v-enter,
+.v-leave-active {
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ border-top-width: 0;
+ border-bottom-width: 0;
+}
+
+.errors {
+ color: #f00;
+}
diff --git a/src/v2/examples/vue-20-github-commits/index.html b/src/v2/examples/vue-20-github-commits/index.html
new file mode 100644
index 0000000000..fcd5d00d68
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/index.html
@@ -0,0 +1,91 @@
+
+
+
+ GitHub Commits
+
+
+
+
+
+
Latest Vue.js Commits
+
+
+ {{ branch }}
+
+
vuejs/vue@{{ currentBranch }}
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-github-commits/package.json b/src/v2/examples/vue-20-github-commits/package.json
new file mode 100644
index 0000000000..8afebc6358
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-github-commits",
+ "version": "1.0.0",
+ "description": "This example fetches latest Vue.js commits data from GitHub's API and displays them as a list. You can switch between the master and dev branches.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-github-commits/sandbox.config.json b/src/v2/examples/vue-20-github-commits/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-github-commits/style.css b/src/v2/examples/vue-20-github-commits/style.css
new file mode 100644
index 0000000000..c0e705b77b
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/style.css
@@ -0,0 +1,15 @@
+#demo {
+ font-family: "Helvetica", Arial, sans-serif;
+}
+a {
+ text-decoration: none;
+ color: #f66;
+}
+li {
+ line-height: 1.5em;
+ margin-bottom: 20px;
+}
+.author,
+.date {
+ font-weight: bold;
+}
diff --git a/src/v2/examples/vue-20-grid-component/index.html b/src/v2/examples/vue-20-grid-component/index.html
new file mode 100644
index 0000000000..40e8a947aa
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/index.html
@@ -0,0 +1,121 @@
+
+
+
+ Grid Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-grid-component/package.json b/src/v2/examples/vue-20-grid-component/package.json
new file mode 100644
index 0000000000..1734610da9
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-grid-component",
+ "version": "1.0.0",
+ "description": "This is an example of creating a reusable grid component and using it with external data.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-grid-component/sandbox.config.json b/src/v2/examples/vue-20-grid-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-grid-component/style.css b/src/v2/examples/vue-20-grid-component/style.css
new file mode 100644
index 0000000000..f10002ab8f
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/style.css
@@ -0,0 +1,60 @@
+body {
+ font-family: Helvetica Neue, Arial, sans-serif;
+ font-size: 14px;
+ color: #444;
+}
+
+table {
+ border: 2px solid #42b983;
+ border-radius: 3px;
+ background-color: #fff;
+}
+
+th {
+ background-color: #42b983;
+ color: rgba(255, 255, 255, 0.66);
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+td {
+ background-color: #f9f9f9;
+}
+
+th,
+td {
+ min-width: 120px;
+ padding: 10px 20px;
+}
+
+th.active {
+ color: #fff;
+}
+
+th.active .arrow {
+ opacity: 1;
+}
+
+.arrow {
+ display: inline-block;
+ vertical-align: middle;
+ width: 0;
+ height: 0;
+ margin-left: 5px;
+ opacity: 0.66;
+}
+
+.arrow.asc {
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-bottom: 4px solid #fff;
+}
+
+.arrow.dsc {
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid #fff;
+}
diff --git a/src/v2/examples/vue-20-hello-world/index.html b/src/v2/examples/vue-20-hello-world/index.html
new file mode 100644
index 0000000000..95121199a6
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/index.html
@@ -0,0 +1,21 @@
+
+
+
+ My first Vue app
+
+
+
+
+ {{ message }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-hello-world/package.json b/src/v2/examples/vue-20-hello-world/package.json
new file mode 100644
index 0000000000..c02e41273c
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-hello-world",
+ "version": "1.0.0",
+ "description": "The easiest way to try out Vue.js, edit this Hello World example",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-hello-world/sandbox.config.json b/src/v2/examples/vue-20-hello-world/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html
new file mode 100644
index 0000000000..339d651065
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Vue Component Blog Post Example
+
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json
new file mode 100644
index 0000000000..7bf11e28e3
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-keep-alive-with-dynamic-components",
+ "version": "1.0.0",
+ "description": "The Posts tab maintains its state (the selected post) even when it's not rendered.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css
new file mode 100644
index 0000000000..5681ac6cb3
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css
@@ -0,0 +1,49 @@
+.tab-button {
+ padding: 6px 10px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border: 1px solid #ccc;
+ cursor: pointer;
+ background: #f0f0f0;
+ margin-bottom: -1px;
+ margin-right: -1px;
+}
+.tab-button:hover {
+ background: #e0e0e0;
+}
+.tab-button.active {
+ background: #e0e0e0;
+}
+.tab {
+ border: 1px solid #ccc;
+ padding: 10px;
+}
+.posts-tab {
+ display: flex;
+}
+.posts-sidebar {
+ max-width: 40vw;
+ margin: 0;
+ padding: 0 10px 0 0;
+ list-style-type: none;
+ border-right: 1px solid #ccc;
+}
+.posts-sidebar li {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ cursor: pointer;
+}
+.posts-sidebar li:hover {
+ background: #eee;
+}
+.posts-sidebar li.selected {
+ background: lightblue;
+}
+.selected-post-container {
+ padding-left: 10px;
+}
+.selected-post > :first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
diff --git a/src/v2/examples/vue-20-list-move-transitions/index.html b/src/v2/examples/vue-20-list-move-transitions/index.html
new file mode 100644
index 0000000000..536a9ba25c
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/index.html
@@ -0,0 +1,43 @@
+
+
+
+ List Move Transitions Sudoku Example
+
+
+
+
+
+
+
Lazy Sudoku
+
Keep hitting the shuffle button until you win.
+
+
+ Shuffle
+
+
+
+ {{ cell.number }}
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-list-move-transitions/package.json b/src/v2/examples/vue-20-list-move-transitions/package.json
new file mode 100644
index 0000000000..f18a53b340
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-list-move-transitions",
+ "version": "1.0.0",
+ "description": "Example showing list entering/leaving transitions in Sudoku.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json b/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-list-move-transitions/style.css b/src/v2/examples/vue-20-list-move-transitions/style.css
new file mode 100644
index 0000000000..103973e3ca
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/style.css
@@ -0,0 +1,25 @@
+.container {
+ display: flex;
+ flex-wrap: wrap;
+ width: 238px;
+ margin-top: 10px;
+}
+.cell {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ width: 25px;
+ height: 25px;
+ border: 1px solid #aaa;
+ margin-right: -1px;
+ margin-bottom: -1px;
+}
+.cell:nth-child(3n) {
+ margin-right: 0;
+}
+.cell:nth-child(27n) {
+ margin-bottom: 0;
+}
+.cell-move {
+ transition: transform 1s;
+}
diff --git a/src/v2/examples/vue-20-markdown-editor/index.html b/src/v2/examples/vue-20-markdown-editor/index.html
new file mode 100644
index 0000000000..e740dfb816
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/index.html
@@ -0,0 +1,35 @@
+
+
+
+ Markdown Editor
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-markdown-editor/package.json b/src/v2/examples/vue-20-markdown-editor/package.json
new file mode 100644
index 0000000000..7866640c16
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-markdown-editor",
+ "version": "1.0.0",
+ "description": "Dead simple Markdown editor.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-markdown-editor/sandbox.config.json b/src/v2/examples/vue-20-markdown-editor/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-markdown-editor/style.css b/src/v2/examples/vue-20-markdown-editor/style.css
new file mode 100644
index 0000000000..01cacdc9d3
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/style.css
@@ -0,0 +1,33 @@
+html,
+body,
+#editor {
+ margin: 0;
+ height: 100%;
+ font-family: "Helvetica Neue", Arial, sans-serif;
+ color: #333;
+}
+
+textarea,
+#editor div {
+ display: inline-block;
+ width: 49%;
+ height: 100%;
+ vertical-align: top;
+ box-sizing: border-box;
+ padding: 0 20px;
+}
+
+textarea {
+ border: none;
+ border-right: 1px solid #ccc;
+ resize: none;
+ outline: none;
+ background-color: #f6f6f6;
+ font-size: 14px;
+ font-family: "Monaco", courier, monospace;
+ padding: 20px;
+}
+
+code {
+ color: #f66;
+}
diff --git a/src/v2/examples/vue-20-modal-component/index.html b/src/v2/examples/vue-20-modal-component/index.html
new file mode 100644
index 0000000000..60235e8e7e
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/index.html
@@ -0,0 +1,69 @@
+
+
+
+ Modal Component
+
+
+
+
+
+
+
+
+ Show Modal
+
+
+
+ custom header
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-modal-component/package.json b/src/v2/examples/vue-20-modal-component/package.json
new file mode 100644
index 0000000000..6d64ba2432
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-modal-component",
+ "version": "1.0.0",
+ "description": "Features used: component, prop passing, content insertion, transitions.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-modal-component/sandbox.config.json b/src/v2/examples/vue-20-modal-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-modal-component/style.css b/src/v2/examples/vue-20-modal-component/style.css
new file mode 100644
index 0000000000..d36f166fb4
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/style.css
@@ -0,0 +1,63 @@
+.modal-mask {
+ position: fixed;
+ z-index: 9998;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: table;
+ transition: opacity 0.3s ease;
+}
+
+.modal-wrapper {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.modal-container {
+ width: 300px;
+ margin: 0px auto;
+ padding: 20px 30px;
+ background-color: #fff;
+ border-radius: 2px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
+ transition: all 0.3s ease;
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+.modal-header h3 {
+ margin-top: 0;
+ color: #42b983;
+}
+
+.modal-body {
+ margin: 20px 0;
+}
+
+.modal-default-button {
+ float: right;
+}
+
+/*
+ * The following styles are auto-applied to elements with
+ * transition="modal" when their visibility is toggled
+ * by Vue.js.
+ *
+ * You can easily play with the modal transition by editing
+ * these styles.
+ */
+
+.modal-enter {
+ opacity: 0;
+}
+
+.modal-leave-active {
+ opacity: 0;
+}
+
+.modal-enter .modal-container,
+.modal-leave-active .modal-container {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+}
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html b/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html
new file mode 100644
index 0000000000..50b2cba0e8
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html
@@ -0,0 +1,47 @@
+
+
+
+ Priority D Rules Correct Example
+
+
+
+
+
+
+
+ Save
+
+
+ Edit
+
+
+
+
+ With a unique key
on each conditional element, the
+ transition is now applied.
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json b/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json
new file mode 100644
index 0000000000..7afc08c225
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-priority-d-rules-correct-example",
+ "version": "1.0.0",
+ "description": "A unique key on each conditional element so the transition is applied.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json b/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html
new file mode 100644
index 0000000000..81951e7667
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html
@@ -0,0 +1,54 @@
+
+
+
+ Priority D Rules Unintended Consequences
+
+
+
+
+
+
+
+ Save
+
+
+ Edit
+
+
+
+
+ When clicking on the <button>
above, the transition
+ is never applied because Vue is reusing the same element for render
+ efficiency. To force Vue to treat these as separate elements, a
+ unique key
must be added
+ to each conditional element.
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json
new file mode 100644
index 0000000000..43c1c3a9f2
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-priority-d-rules-unintended-consequences",
+ "version": "1.0.0",
+ "description": "Lacking a unique key on each conditional element, the transition is never applied.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/index.html b/src/v2/examples/vue-20-programmatic-event-listeners/index.html
new file mode 100644
index 0000000000..ba0503c97d
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/index.html
@@ -0,0 +1,32 @@
+
+
+
+ Programmatic Event Listeners using Pikaday
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/package.json b/src/v2/examples/vue-20-programmatic-event-listeners/package.json
new file mode 100644
index 0000000000..42312caa1f
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-programmatic-event-listeners",
+ "version": "1.0.0",
+ "description": "Vue.js Programmatic Event Listeners example using Pikaday",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json b/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html b/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html
new file mode 100644
index 0000000000..e9396f3868
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html
@@ -0,0 +1,184 @@
+
+
+
+ Realtime with deepstreamHub
+
+
+
+
+
+
+
+
+
+ Connection-State is: {{connectionState}}
+
+
+
+
+
+
+
+
+
Realtime Datastore
+
+ Firstname
+
+
+
+ Lastname
+
+
+
+
+
+
+
+
+
Publish
+
+ Send test-event with
+
+
+
+
+
+
+
+
+
+
+
Request
+
+ Make multiply request
+
+
+
+ {{displayResponse}}
+
+
+
+
Response
+
Multiply number with:
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json b/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json
new file mode 100644
index 0000000000..abf1458b23
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-realtime-with-deepstreamhub",
+ "version": "1.0.0",
+ "description": "This example uses deepstreamHub to synchronize realtime data, send events and make remote procedure calls between clients (you can try opening it in multiple browser windows).",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json b/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css b/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css
new file mode 100644
index 0000000000..b643051dfb
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css
@@ -0,0 +1,122 @@
+* {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ font-family: RobotoCondensed, sans-serif;
+ font-size: 14px;
+ color: #333;
+ box-sizing: border-box;
+ outline: none;
+ transition: all 200ms ease;
+}
+
+body {
+ background-color: #fff;
+}
+
+.group {
+ width: 80%;
+ max-width: 800px;
+ margin: 40px auto;
+ padding: 20px;
+ position: relative;
+ overflow: hidden;
+}
+
+.group.connectionState {
+ margin: 10px auto 0;
+ padding: 0 20px;
+}
+
+h2 {
+ font-size: 20px;
+ border-bottom: 1px solid #ccc;
+ padding-bottom: 4px;
+ margin-bottom: 10px;
+ position: relative;
+}
+
+h2 small {
+ position: absolute;
+ right: 0;
+}
+
+h2 small * {
+ display: inline-block;
+ vertical-align: middle;
+ font-weight: normal;
+ color: #333;
+ font-size: 12px;
+ cursor: pointer;
+}
+
+button,
+input,
+.item {
+ height: 32px;
+ padding: 6px;
+}
+
+button {
+ border: none;
+ background: #7185ec;
+ color: #fff;
+ font-weight: 500;
+ border-radius: 4px;
+ cursor: pointer;
+ text-align: center;
+ cursor: pointer;
+ font-weight: bold;
+ box-shadow: 1px 1px 3px 0px rgba(0, 0, 0, 0.2);
+}
+
+button:hover {
+ background-color: #586cd8;
+}
+
+button:active {
+ position: relative;
+ top: 1px;
+ left: 1px;
+ box-shadow: none;
+}
+
+.half {
+ width: 48%;
+ float: left;
+ position: relative;
+}
+
+.half.left {
+ margin-right: 4%;
+}
+
+label {
+ font-size: 11px;
+ font-style: italic;
+}
+
+input {
+ border-radius: 4px;
+ border: 1px solid #ccc;
+}
+
+input:focus {
+ border-color: #7185ec;
+}
+
+.input-group input {
+ width: 100%;
+}
+
+span.response {
+ display: inline-block;
+ background-color: #dddddd;
+}
+
+@media screen and (max-width: 900px) {
+ .half {
+ width: 100%;
+ margin: 0 0 10px !important;
+ }
+}
diff --git a/src/v2/examples/vue-20-single-file-components/Hello.vue b/src/v2/examples/vue-20-single-file-components/Hello.vue
new file mode 100644
index 0000000000..9ca04cbb4c
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/Hello.vue
@@ -0,0 +1,20 @@
+
+ {{ greeting }} World!
+
+
+
+
+
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-single-file-components/index.html b/src/v2/examples/vue-20-single-file-components/index.html
new file mode 100644
index 0000000000..865e670f40
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-single-file-components/index.js b/src/v2/examples/vue-20-single-file-components/index.js
new file mode 100644
index 0000000000..4cd7af61fb
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/index.js
@@ -0,0 +1,10 @@
+import Vue from "vue";
+import App from "./Hello";
+
+Vue.config.productionTip = false;
+
+new Vue({
+ el: "#app",
+ template: " ",
+ components: { App }
+});
diff --git a/src/v2/examples/vue-20-single-file-components/package.json b/src/v2/examples/vue-20-single-file-components/package.json
new file mode 100644
index 0000000000..36dd9df6e4
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "vue-20-single-file-components",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "vue": "^2.6.11"
+ },
+ "devDependencies": {},
+ "browserslist": ["> 1%", "last 2 versions", "not ie <= 8"],
+ "keywords": [],
+ "description": "Hello.vue single-file components example using a .vue extension."
+}
diff --git a/src/v2/examples/vue-20-svg-graph/index.html b/src/v2/examples/vue-20-svg-graph/index.html
new file mode 100644
index 0000000000..885a3fbbef
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/index.html
@@ -0,0 +1,142 @@
+
+
+
+ SVG Graph
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{stat.label}}
+
+ {{stat.value}}
+ X
+
+
+
{{ stats }}
+
+
+ * input[type="range"] requires IE10 or above.
+
+
+
+
diff --git a/src/v2/examples/vue-20-svg-graph/package.json b/src/v2/examples/vue-20-svg-graph/package.json
new file mode 100644
index 0000000000..afbe362f77
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-svg-graph",
+ "version": "1.0.0",
+ "description": "This example showcases a combination of custom component, computed property, two-way binding and SVG support.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-svg-graph/sandbox.config.json b/src/v2/examples/vue-20-svg-graph/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-svg-graph/style.css b/src/v2/examples/vue-20-svg-graph/style.css
new file mode 100644
index 0000000000..b533e006a6
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/style.css
@@ -0,0 +1,31 @@
+body {
+ font-family: Helvetica Neue, Arial, sans-serif;
+}
+
+polygon {
+ fill: #42b983;
+ opacity: 0.75;
+}
+
+circle {
+ fill: transparent;
+ stroke: #999;
+}
+
+text {
+ font-family: Helvetica Neue, Arial, sans-serif;
+ font-size: 10px;
+ fill: #666;
+}
+
+label {
+ display: inline-block;
+ margin-left: 10px;
+ width: 20px;
+}
+
+#raw {
+ position: absolute;
+ top: 0;
+ left: 300px;
+}
diff --git a/src/v2/examples/vue-20-template-compilation/index.html b/src/v2/examples/vue-20-template-compilation/index.html
new file mode 100644
index 0000000000..1582c6ea42
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/index.html
@@ -0,0 +1,83 @@
+
+
+
+ Template Compilation
+
+
+
+
+
+
+
+
render:
+
{{ result.render }}
+
staticRenderFns:
+
_m({{ index }}): {{ fn }}
+
{{ result.staticRenderFns }}
+
+
+
Compilation Error:
+
{{ result }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-template-compilation/package.json b/src/v2/examples/vue-20-template-compilation/package.json
new file mode 100644
index 0000000000..c802e56604
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-template-compilation",
+ "version": "1.0.0",
+ "description": "A demo using Vue.compile to live-compile a template string.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-template-compilation/sandbox.config.json b/src/v2/examples/vue-20-template-compilation/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-template-compilation/style.css b/src/v2/examples/vue-20-template-compilation/style.css
new file mode 100644
index 0000000000..02a88e4503
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/style.css
@@ -0,0 +1,45 @@
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
+ -webkit-user-select: inherit;
+ user-select: inherit;
+ font-size: 14px;
+ color: #34495e;
+}
+
+pre {
+ padding: 10px;
+ overflow-x: auto;
+ background: #f2f2f2;
+}
+
+code {
+ white-space: pre;
+ padding: 0;
+}
+
+code,
+pre,
+textarea {
+ font-family: "Roboto Mono", Monaco, courier, monospace;
+}
+
+textarea {
+ width: 100%;
+ font-size: 14px;
+ margin-bottom: 8px;
+ border-color: #bbb;
+ padding: 8px;
+ border-bottom-width: 2px;
+ outline: none;
+ color: #34495e;
+}
+
+textarea:focus {
+ background: lightyellow;
+}
diff --git a/src/v2/examples/vue-20-todomvc/index.html b/src/v2/examples/vue-20-todomvc/index.html
new file mode 100644
index 0000000000..04463a3b7c
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/index.html
@@ -0,0 +1,258 @@
+
+
+
+ TodoMVC
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-todomvc/package.json b/src/v2/examples/vue-20-todomvc/package.json
new file mode 100644
index 0000000000..8fb7dbe6d5
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-todomvc",
+ "version": "1.0.0",
+ "description": "This is a fully spec-compliant TodoMVC implementation in under 120 effective lines of JavaScript (excluding comments and blank lines).",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-todomvc/sandbox.config.json b/src/v2/examples/vue-20-todomvc/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-tree-view/index.html b/src/v2/examples/vue-20-tree-view/index.html
new file mode 100644
index 0000000000..63476085e2
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/index.html
@@ -0,0 +1,121 @@
+
+
+
+ Tree View
+
+
+
+
+
+
+
+ (You can double click on an item to turn it into a folder.)
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-tree-view/package.json b/src/v2/examples/vue-20-tree-view/package.json
new file mode 100644
index 0000000000..911f9e37e4
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-tree-view",
+ "version": "1.0.0",
+ "description": "Example of a simple tree view implementation showcasing recursive usage of components.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-tree-view/sandbox.config.json b/src/v2/examples/vue-20-tree-view/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-tree-view/style.css b/src/v2/examples/vue-20-tree-view/style.css
new file mode 100644
index 0000000000..39c9133b8c
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/style.css
@@ -0,0 +1,15 @@
+body {
+ font-family: Menlo, Consolas, monospace;
+ color: #444;
+}
+.item {
+ cursor: pointer;
+}
+.bold {
+ font-weight: bold;
+}
+ul {
+ padding-left: 1em;
+ line-height: 1.5em;
+ list-style-type: dot;
+}
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js b/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js
new file mode 100644
index 0000000000..80ab295e34
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js
@@ -0,0 +1,61 @@
+var currencyValidator = {
+ format: function(number) {
+ return (Math.trunc(number * 100) / 100).toFixed(2);
+ },
+ parse: function(newString, oldNumber) {
+ var CleanParse = function(value) {
+ return { value: value };
+ };
+ var CurrencyWarning = function(warning, value) {
+ return {
+ warning: warning,
+ value: value,
+ attempt: newString
+ };
+ };
+ var NotAValidDollarAmountWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " is not a valid dollar amount",
+ value
+ );
+ };
+ var AutomaticConversionWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " was automatically converted to " + value,
+ value
+ );
+ };
+
+ var newNumber = Number(newString);
+ var indexOfDot = newString.indexOf(".");
+ var indexOfE = newString.indexOf("e");
+
+ if (isNaN(newNumber)) {
+ if (
+ indexOfDot === -1 &&
+ indexOfE > 0 &&
+ indexOfE === newString.length - 1 &&
+ Number(newString.slice(0, indexOfE)) !== 0
+ ) {
+ return new CleanParse(oldNumber);
+ } else {
+ return new NotAValidDollarAmountWarning(oldNumber);
+ }
+ }
+
+ var newCurrencyString = currencyValidator.format(newNumber);
+ var newCurrencyNumber = Number(newCurrencyString);
+
+ if (newCurrencyNumber === newNumber) {
+ if (indexOfE !== -1 && indexOfE === newString.length - 2) {
+ return new AutomaticConversionWarning(newNumber);
+ } else {
+ return new CleanParse(newNumber);
+ }
+ } else {
+ return new NotAValidDollarAmountWarning(
+ newNumber > newCurrencyNumber ? newCurrencyNumber : oldNumber
+ );
+ }
+ }
+};
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/index.html b/src/v2/examples/vue-20-two-way-currency-filter/index.html
new file mode 100644
index 0000000000..c3fd6e2550
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/index.html
@@ -0,0 +1,90 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/package.json b/src/v2/examples/vue-20-two-way-currency-filter/package.json
new file mode 100644
index 0000000000..ef67bd57a8
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-two-way-currency-filter",
+ "version": "1.0.0",
+ "description": "Using lifecycle hooks and DOM events in place of the hidden behavior of two-way filters",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json b/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-wrapper-component/index.html b/src/v2/examples/vue-20-wrapper-component/index.html
new file mode 100644
index 0000000000..7ee7577af8
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/index.html
@@ -0,0 +1,90 @@
+
+
+
+ Wrapper Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-wrapper-component/package.json b/src/v2/examples/vue-20-wrapper-component/package.json
new file mode 100644
index 0000000000..92fe02c5c7
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-wrapper-component",
+ "version": "1.0.0",
+ "description": "In this example we are integrating a 3rd party jQuery plugin (select2) by wrapping it inside a custom component.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-wrapper-component/sandbox.config.json b/src/v2/examples/vue-20-wrapper-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/guide/class-and-style.md b/src/v2/guide/class-and-style.md
index 2c40d5033c..60171d440b 100644
--- a/src/v2/guide/class-and-style.md
+++ b/src/v2/guide/class-and-style.md
@@ -7,6 +7,7 @@ order: 6
A common need for data binding is manipulating an element's class list and its inline styles. Since they are both attributes, we can use `v-bind` to handle them: we only need to calculate a final string with our expressions. However, meddling with string concatenation is annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays.
## Binding HTML Classes
+
### Object Syntax
diff --git a/src/v2/guide/comparison.md b/src/v2/guide/comparison.md
index 7906ae506f..c4b87ffd4d 100644
--- a/src/v2/guide/comparison.md
+++ b/src/v2/guide/comparison.md
@@ -8,7 +8,7 @@ This is definitely the most difficult page in the guide to write, but we do feel
We also try very hard to avoid bias. As the core team, we obviously like Vue a lot. There are some problems we think it solves better than anything else out there. If we didn't believe that, we wouldn't be working on it. We do want to be fair and accurate though. Where other libraries offer significant advantages, such as React's vast ecosystem of alternative renderers or Knockout's browser support back to IE6, we try to list these as well.
-We'd also like **your** help keeping this document up-to-date because the JavaScript world moves fast! If you notice an inaccuracy or something that doesn't seem quite right, please let us know by [opening an issue](https://github.com/vuejs/vuejs.org/issues/new?title=Inaccuracy+in+comparisons+guide).
+We'd also like **your** help keeping this document up-to-date because the JavaScript world moves fast! If you notice an inaccuracy or something that doesn't seem quite right, please let us know by [opening an issue](https://github.com/vuejs/v2.vuejs.org/issues/new?title=Inaccuracy+in+comparisons+guide).
## React
@@ -68,7 +68,7 @@ On a higher level, we can divide components into two categories: presentational
#### Component-Scoped CSS
-Unless you spread components out over multiple files (for example with [CSS Modules](https://github.com/gajus/react-css-modules)), scoping CSS in React is often done via CSS-in-JS solutions (e.g. [styled-components](https://github.com/styled-components/styled-components), [glamorous](https://github.com/paypal/glamorous), and [emotion](https://github.com/emotion-js/emotion)). This introduces a new component-oriented styling paradigm that is different from the normal CSS authoring process. Additionally, although there is support for extracting CSS into a single stylesheet at build time, it is still common that a runtime will need to be included in the bundle for styling to work properly. While you gain access to the dynamism of JavaScript while constructing your styles, the tradeoff is often increased bundle size and runtime cost.
+Unless you spread components out over multiple files (for example with [CSS Modules](https://github.com/gajus/react-css-modules)), scoping CSS in React is often done via CSS-in-JS solutions (e.g. [styled-components](https://github.com/styled-components/styled-components) and [emotion](https://github.com/emotion-js/emotion)). This introduces a new component-oriented styling paradigm that is different from the normal CSS authoring process. Additionally, although there is support for extracting CSS into a single stylesheet at build time, it is still common that a runtime will need to be included in the bundle for styling to work properly. While you gain access to the dynamism of JavaScript while constructing your styles, the tradeoff is often increased bundle size and runtime cost.
If you are a fan of CSS-in-JS, many of the popular CSS-in-JS libraries support Vue (e.g. [styled-components-vue](https://github.com/styled-components/vue-styled-components) and [vue-emotion](https://github.com/egoist/vue-emotion)). The main difference between React and Vue here is that the default method of styling in Vue is through more familiar `style` tags in [single-file components](single-file-components.html).
@@ -96,11 +96,11 @@ For large applications, both Vue and React offer robust routing solutions. The R
Another important difference between these offerings is that Vue's companion libraries for state management and routing (among [other concerns](https://github.com/vuejs)) are all officially supported and kept up-to-date with the core library. React instead chooses to leave these concerns to the community, creating a more fragmented ecosystem. Being more popular though, React's ecosystem is considerably richer than Vue's.
-Finally, Vue offers a [CLI project generator](https://github.com/vuejs/vue-cli) that makes it trivially easy to start a new project using your choice of build system, including [webpack](https://github.com/vuejs-templates/webpack), [Browserify](https://github.com/vuejs-templates/browserify), or even [no build system](https://github.com/vuejs-templates/simple). React is also making strides in this area with [create-react-app](https://github.com/facebookincubator/create-react-app), but it currently has a few limitations:
+Finally, Vue offers a [CLI project generator](https://github.com/vuejs/vue-cli) that makes it trivially easy to start a new project by featuring an interactive project scaffolding wizard. You can even use it for [instantly prototyping](https://cli.vuejs.org/guide/prototyping.html#instant-prototyping) a component. React is also making strides in this area with [create-react-app](https://github.com/facebookincubator/create-react-app), but it currently has a few limitations:
-- It does not allow any configuration during project generation, while Vue's project templates allow [Yeoman](http://yeoman.io/)-like customization.
-- It only offers a single template that assumes you're building a single-page application, while Vue offers a wide variety of templates for various purposes and build systems.
-- It cannot generate projects from user-built templates, which can be especially useful for enterprise environments with pre-established conventions.
+- It does not allow any configuration during project generation, while Vue CLI runs on top of an upgradeable runtime dependency that can be extended via [plugins](https://cli.vuejs.org/guide/plugins-and-presets.html#plugins).
+- It only offers a single template that assumes you're building a single-page application, while Vue offers a wide variety of default options for various purposes and build systems.
+- It cannot generate projects from user-built [presets](https://cli.vuejs.org/guide/plugins-and-presets.html#presets), which can be especially useful for enterprise environments with pre-established conventions.
It's important to note that many of these limitations are intentional design decisions made by the create-react-app team and they do have their advantages. For example, as long as your project's needs are very simple and you never need to "eject" to customize your build process, you'll be able to update it as a dependency. You can read more about the [differing philosophy here](https://github.com/facebookincubator/create-react-app#philosophy).
@@ -111,7 +111,7 @@ React is renowned for its steep learning curve. Before you can really get starte
While Vue scales up just as well as React, it also scales down just as well as jQuery. That's right - to get started, all you have to do is drop a single script tag into the page:
``` html
-
+
```
Then you can start writing Vue code and even ship the minified version to production without feeling guilty or having to worry about performance problems.
@@ -224,5 +224,5 @@ In Polymer, the team has also made its data-binding system very limited in order
Riot 3.0 provides a similar component-based development model (which is called a "tag" in Riot), with a minimal and beautifully designed API. Riot and Vue probably share a lot in design philosophies. However, despite being a bit heavier than Riot, Vue does offer some significant advantages:
-- Better performance. Riot [traverses a DOM tree](http://riotjs.com/compare/#virtual-dom-vs-expressions-binding) rather than using a virtual DOM, so suffers from the same performance issues as AngularJS.
+- Better performance. Riot [traverses a DOM tree](https://v3.riotjs.now.sh/compare/#virtual-dom-vs-expressions-binding) rather than using a virtual DOM, so suffers from the same performance issues as AngularJS.
- More mature tooling support. Vue provides official support for [webpack](https://github.com/vuejs/vue-loader) and [Browserify](https://github.com/vuejs/vueify), while Riot relies on community support for build system integration.
diff --git a/src/v2/guide/components-custom-events.md b/src/v2/guide/components-custom-events.md
index 20748ba091..1df316204a 100644
--- a/src/v2/guide/components-custom-events.md
+++ b/src/v2/guide/components-custom-events.md
@@ -6,6 +6,8 @@ order: 103
> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+
## Event Names
Unlike components and props, event names don't provide any automatic case transformation. Instead, the name of an emitted event must exactly match the name used to listen to that event. For example, if emitting a camelCased event name:
@@ -58,7 +60,7 @@ Now when using `v-model` on this component:
the value of `lovingVue` will be passed to the `checked` prop. The `lovingVue` property will then be updated when `` emits a `change` event with a new value.
-Note that you still have to declare the checked
prop in component's props
option.
+Note that you still have to declare the checked
prop in the component's props
option.
## Binding Native Events to Components
diff --git a/src/v2/guide/components-dynamic-async.md b/src/v2/guide/components-dynamic-async.md
index 5d589d1906..2a159364de 100644
--- a/src/v2/guide/components-dynamic-async.md
+++ b/src/v2/guide/components-dynamic-async.md
@@ -4,6 +4,12 @@ type: guide
order: 105
---
+
+
> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
## `keep-alive` with Dynamic Components
@@ -106,6 +112,7 @@ new Vue({
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
+ overflow-anchor: none;
}
.dynamic-component-demo-tab-button:hover {
background: #e0e0e0;
@@ -193,7 +200,7 @@ new Vue({
{% endraw %}
-Now the _Posts_ tab maintains its state (the selected post) even when it's not rendered. See [this fiddle](https://jsfiddle.net/chrisvfritz/Lp20op9o/) for the complete code.
+Now the _Posts_ tab maintains its state (the selected post) even when it's not rendered. See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-keep-alive-with-dynamic-components) for the complete code.
Note that `` requires the components being switched between to all have names, either using the `name` option on a component, or through local/global registration.
@@ -201,6 +208,8 @@ Check out more details on `` in the [API reference](../api/#keep-ali
## Async Components
+
+
In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's needed. To make that easier, Vue allows you to define your component as a factory function that asynchronously resolves your component definition. Vue will only trigger the factory function when the component needs to be rendered and will cache the result for future re-renders. For example:
``` js
@@ -225,12 +234,12 @@ Vue.component('async-webpack-example', function (resolve) {
})
```
-You can also return a `Promise` in the factory function, so with Webpack 2 and ES2015 syntax you can do:
+You can also return a `Promise` in the factory function, so with Webpack 2 and ES2015 syntax you can make use of dynamic imports:
``` js
Vue.component(
'async-webpack-example',
- // The `import` function returns a Promise.
+ // A dynamic import returns a Promise.
() => import('./my-async-component')
)
```
@@ -246,7 +255,7 @@ new Vue({
})
```
-If you're a Browserify user that would like to use async components, its creator has unfortunately [made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224) that async loading "is not something that Browserify will ever support." Officially, at least. The Browserify community has found [some workarounds](https://github.com/vuejs/vuejs.org/issues/620), which may be helpful for existing and complex applications. For all other scenarios, we recommend using Webpack for built-in, first-class async support.
+If you're a Browserify user that would like to use async components, its creator has unfortunately [made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224) that async loading "is not something that Browserify will ever support." Officially, at least. The Browserify community has found [some workarounds](https://github.com/vuejs/v2.vuejs.org/issues/620), which may be helpful for existing and complex applications. For all other scenarios, we recommend using Webpack for built-in, first-class async support.
### Handling Loading State
diff --git a/src/v2/guide/components-edge-cases.md b/src/v2/guide/components-edge-cases.md
index c8a6a49eae..ce67f1b0e5 100644
--- a/src/v2/guide/components-edge-cases.md
+++ b/src/v2/guide/components-edge-cases.md
@@ -63,7 +63,7 @@ There are cases however, particularly shared component libraries, when this _mig
```
-The `` component might define a `map` property that all subcomponents need access to. In this case `` might want to access that map with something like `this.$parent.getMap`, in order to add a set of markers to it. You can see this pattern [in action here](https://jsfiddle.net/chrisvfritz/ttzutdxh/).
+The `` component might define a `map` property that all subcomponents need access to. In this case `` might want to access that map with something like `this.$parent.getMap`, in order to add a set of markers to it. You can see this pattern [in action here](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-accessing-parent-component-instance).
Keep in mind, however, that components built with this pattern are still inherently fragile. For example, imagine we add a new `` component and when `` appears within that, it should only render markers that fall within that region:
@@ -81,7 +81,7 @@ Then inside `` you might find yourself reaching for a hack l
var map = this.$parent.map || this.$parent.$parent.map
```
-This has quickly gotten out of hand. That's why to provide context information to descendent components arbitrarily deep, we instead recommend [dependency injection](#Dependency-Injection).
+This has quickly gotten out of hand. That's why to provide context information to descendant components arbitrarily deep, we instead recommend [dependency injection](#Dependency-Injection).
### Accessing Child Component Instances & Child Elements
@@ -138,7 +138,7 @@ Earlier, when we described [Accessing the Parent Component Instance](#Accessing-
In this component, all descendants of `` needed access to a `getMap` method, in order to know which map to interact with. Unfortunately, using the `$parent` property didn't scale well to more deeply nested components. That's where dependency injection can be useful, using two new instance options: `provide` and `inject`.
-The `provide` options allows us to specify the data/methods we want to **provide** to descendent components. In this case, that's the `getMap` method inside ``:
+The `provide` options allows us to specify the data/methods we want to **provide** to descendant components. In this case, that's the `getMap` method inside ``:
```js
provide: function () {
@@ -154,7 +154,7 @@ Then in any descendants, we can use the `inject` option to receive specific prop
inject: ['getMap']
```
-You can see the [full example here](https://jsfiddle.net/chrisvfritz/tdv8dt3s/). The advantage over using `$parent` is that we can access `getMap` in _any_ descendant component, without exposing the entire instance of ``. This allows us to more safely keep developing that component, without fear that we might change/remove something that a child component is relying on. The interface between these components remains clearly defined, just as with `props`.
+You can see the [full example here](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dependency-injection). The advantage over using `$parent` is that we can access `getMap` in _any_ descendant component, without exposing the entire instance of ``. This allows us to more safely keep developing that component, without fear that we might change/remove something that a child component is relying on. The interface between these components remains clearly defined, just as with `props`.
In fact, you can think of dependency injection as sort of "long-range props", except:
@@ -163,7 +163,7 @@ In fact, you can think of dependency injection as sort of "long-range props", ex
However, there are downsides to dependency injection. It couples components in your application to the way they're currently organized, making refactoring more difficult. Provided properties are also not reactive. This is by design, because using them to create a central data store scales just as poorly as using $root
for the same purpose. If the properties you want to share are specific to your app, rather than generic, or if you ever want to update provided data inside ancestors, then that's a good sign that you probably need a real state management solution like Vuex instead.
-Learn more about dependency injection in [the API doc](https://vuejs.org/v2/api/#provide-inject).
+Learn more about dependency injection in [the API doc](/v2/api/#provide-inject).
## Programmatic Event Listeners
@@ -233,9 +233,9 @@ methods: {
}
```
-See [this fiddle](https://jsfiddle.net/chrisvfritz/1Leb7up8/) for the full code. Note, however, that if you find yourself having to do a lot of setup and cleanup within a single component, the best solution will usually be to create more modular components. In this case, we'd recommend creating a reusable `` component.
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-programmatic-event-listeners) for the full code. Note, however, that if you find yourself having to do a lot of setup and cleanup within a single component, the best solution will usually be to create more modular components. In this case, we'd recommend creating a reusable `` component.
-To learn more about programmatic listeners, check out the API for [Events Instance Methods](https://vuejs.org/v2/api/#Instance-Methods-Events).
+To learn more about programmatic listeners, check out the API for [Events Instance Methods](/v2/api/#Instance-Methods-Events).
Note that Vue's event system is different from the browser's EventTarget API . Though they work similarly, $emit
, $on
, and $off
are not aliases for dispatchEvent
, addEventListener
, and removeEventListener
.
@@ -288,7 +288,7 @@ Then a `tree-folder-contents` component with this template:
```
-When you look closely, you'll see that these components will actually be each other's descendent _and_ ancestor in the render tree - a paradox! When registering components globally with `Vue.component`, this paradox is resolved for you automatically. If that's you, you can stop reading here.
+When you look closely, you'll see that these components will actually be each other's descendant _and_ ancestor in the render tree - a paradox! When registering components globally with `Vue.component`, this paradox is resolved for you automatically. If that's you, you can stop reading here.
However, if you're requiring/importing components using a __module system__, e.g. via Webpack or Browserify, you'll get an error:
@@ -363,7 +363,7 @@ Thanks to Vue's Reactivity system, it always knows when to update (if you use it
If you find yourself needing to force an update in Vue, in 99.99% of cases, you've made a mistake somewhere.
-You may not have accounted for change detection caveats [with arrays](https://vuejs.org/v2/guide/list.html#Caveats) or [objects](https://vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats), or you may be relying on state that isn't tracked by Vue's reactivity system, e.g. with `data`.
+You may not have accounted for change detection caveats [with arrays](/v2/guide/list.html#Caveats) or [objects](/v2/guide/list.html#Object-Change-Detection-Caveats), or you may be relying on state that isn't tracked by Vue's reactivity system, e.g. with `data`.
However, if you've ruled out the above and find yourself in this extremely rare situation of having to manually force an update, you can do so with [`$forceUpdate`](../api/#vm-forceUpdate).
diff --git a/src/v2/guide/components-props.md b/src/v2/guide/components-props.md
index d4ccbc1b67..1f274c595a 100644
--- a/src/v2/guide/components-props.md
+++ b/src/v2/guide/components-props.md
@@ -4,8 +4,16 @@ type: guide
order: 102
---
+
+
> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+
## Prop Casing (camelCase vs kebab-case)
HTML attribute names are case-insensitive, so browsers will interpret any uppercase characters as lowercase. That means when you're using in-DOM templates, camelCased prop names need to use their kebab-cased (hyphen-delimited) equivalents:
@@ -183,7 +191,7 @@ There are usually two cases where it's tempting to mutate a prop:
## Prop Validation
-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.
+Components can specify requirements for their 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:
@@ -217,7 +225,7 @@ Vue.component('my-component', {
propF: {
validator: function (value) {
// The value must match one of these strings
- return ['success', 'warning', 'danger'].indexOf(value) !== -1
+ return ['success', 'warning', 'danger'].includes(value)
}
}
}
@@ -345,6 +353,7 @@ This pattern allows you to use base components more like raw HTML elements, with
```html
This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+
## Component Names
When registering a component, it will always be given a name. For example, in the global registration we've seen so far:
diff --git a/src/v2/guide/components.md b/src/v2/guide/components.md
index 038d803e74..6a49d9a6fe 100644
--- a/src/v2/guide/components.md
+++ b/src/v2/guide/components.md
@@ -4,6 +4,8 @@ type: guide
order: 11
---
+
+
## Base Example
Here's an example of a Vue component:
@@ -201,7 +203,7 @@ Then want to render a component for each one:
>
```
-Above, you'll see that we can use `v-bind` to dynamically pass props. This is especially useful when you don't know the exact content you're going to render ahead of time, like when [fetching posts from an API](https://jsfiddle.net/chrisvfritz/sbLgr0ad).
+Above, you'll see that we can use `v-bind` to dynamically pass props. This is especially useful when you don't know the exact content you're going to render ahead of time, like when [fetching posts from an API](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-component-blog-post-example).
That's all you need to know about props for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Props](components-props.html).
@@ -220,7 +222,7 @@ At the very least, you'll want to include the post's content:
```
-If you try this in your template however, Vue will show an error, explaining that **every component must have a single root element**. You can fix this error by wrapping the template in a parent element, such as:
+If you try this in your template, however, Vue will show an error, explaining that **every component must have a single root element**. You can fix this error by wrapping the template in a parent element, such as:
```html
@@ -599,7 +601,9 @@ In the example above, `currentTabComponent` can contain either:
- the name of a registered component, or
- a component's options object
-See [this fiddle](https://jsfiddle.net/chrisvfritz/o3nycadu/) to experiment with the full code, or [this version](https://jsfiddle.net/chrisvfritz/b2qj69o1/) for an example binding to a component's options object, instead of its registered name.
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components) to experiment with the full code, or [this version](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components-with-binding) for an example binding to a component's options object, instead of its registered name.
+
+Keep in mind that this attribute can be used with regular HTML elements, however they will be treated as components, which means all attributes **will be bound as DOM attributes**. For some properties such as `value` to work as you would expect, you will need to bind them using the [`.prop` modifier](../api/#v-bind).
That's all you need to know about dynamic components for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Dynamic & Async Components](components-dynamic-async.html).
diff --git a/src/v2/guide/computed.md b/src/v2/guide/computed.md
index 48a194e1f6..290e89e046 100644
--- a/src/v2/guide/computed.md
+++ b/src/v2/guide/computed.md
@@ -4,8 +4,16 @@ type: guide
order: 5
---
+
+
## Computed Properties
+
+
In-template expressions are very convenient, but they are meant for simple operations. Putting too much logic in your templates can make them bloated and hard to maintain. For example:
``` html
@@ -94,7 +102,7 @@ methods: {
}
```
-Instead of a computed property, we can define the same function as a method instead. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their reactive dependencies.** A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as `message` has not changed, multiple access to the `reversedMessage` computed property will immediately return the previously computed result without having to run the function again.
+Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their reactive dependencies.** A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as `message` has not changed, multiple access to the `reversedMessage` computed property will immediately return the previously computed result without having to run the function again.
This also means the following computed property will never update, because `Date.now()` is not a reactive dependency:
diff --git a/src/v2/guide/conditional.md b/src/v2/guide/conditional.md
index b90c3cc15e..d667ae5d73 100644
--- a/src/v2/guide/conditional.md
+++ b/src/v2/guide/conditional.md
@@ -4,6 +4,8 @@ type: guide
order: 7
---
+
+
## `v-if`
The directive `v-if` is used to conditionally render a block. The block will only be rendered if the directive's expression returns a truthy value.
diff --git a/src/v2/guide/custom-directive.md b/src/v2/guide/custom-directive.md
index 8de02de807..5951f163f9 100644
--- a/src/v2/guide/custom-directive.md
+++ b/src/v2/guide/custom-directive.md
@@ -6,6 +6,8 @@ order: 302
## Intro
+
+
In addition to the default set of directives shipped in core (`v-model` and `v-show`), Vue also allows you to register your own custom directives. Note that in Vue 2.0, the primary form of code reuse and abstraction is components - however there may be cases where you need some low-level DOM access on plain elements, and this is where custom directives would still be useful. An example would be focusing on an input element, like this one:
{% raw %}
@@ -199,6 +201,7 @@ new Vue({
```
Result:
+
{% raw %}
+
## Getting Started
@@ -20,23 +20,23 @@ If you are an experienced frontend developer and want to know how Vue compares t
The official guide assumes intermediate level knowledge of HTML, CSS, and JavaScript. If you are totally new to frontend development, it might not be the best idea to jump right into a framework as your first step - grasp the basics then come back! Prior experience with other frameworks helps, but is not required.
-The easiest way to try out Vue.js is using the [JSFiddle Hello World example](https://jsfiddle.net/chrisvfritz/50wL7mdz/). Feel free to open it in another tab and follow along as we go through some basic examples. Or, you can create an index.html
file and include Vue with:
+The easiest way to try out Vue.js is using the [Hello World example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-hello-world). Feel free to open it in another tab and follow along as we go through some basic examples. Or, you can create an index.html
file and include Vue with:
``` html
-
+
```
or:
``` html
-
+
```
The [Installation](installation.html) page provides more options of installing Vue. Note: We **do not** recommend that beginners start with `vue-cli`, especially if you are not yet familiar with Node.js-based build tools.
-If you prefer something more interactive, you can also check out [this tutorial series on Scrimba](https://scrimba.com/playlist/pXKqta), which gives you a mix of screencast and code playground that you can pause and play around with anytime.
+If you prefer something more interactive, you can also check out [this tutorial series on Scrimba](https://scrimba.com/g/gvuedocs), which gives you a mix of screencast and code playground that you can pause and play around with anytime.
## Declarative Rendering
@@ -73,6 +73,8 @@ var app = new Vue({
We have already created our very first Vue app! This looks pretty similar to rendering a string template, but Vue has done a lot of work under the hood. The data and the DOM are now linked, and everything is now **reactive**. How do we know? Open your browser's JavaScript console (right now, on this page) and set `app.message` to a different value. You should see the rendered example above update accordingly.
+Note that we no longer have to interact with the HTML directly. A Vue app attaches itself to a single DOM element (`#app` in our case) then fully controls it. The HTML is our entry point, but everything else happens within the newly created Vue instance.
+
In addition to text interpolation, we can also bind element attributes like this:
``` html
@@ -290,6 +292,8 @@ In Vue, a component is essentially a Vue instance with pre-defined options. Regi
Vue.component('todo-item', {
template: 'This is a todo '
})
+
+var app = new Vue(...)
```
Now you can compose it in another component's template:
@@ -401,4 +405,4 @@ Although Vue doesn't use custom elements internally, it has [great interoperabil
We've briefly introduced the most basic features of Vue.js core - the rest of this guide will cover them and other advanced features with much finer details, so make sure to read through it all!
-
+
diff --git a/src/v2/guide/installation.md b/src/v2/guide/installation.md
index 765d2c89e0..23abed94c0 100644
--- a/src/v2/guide/installation.md
+++ b/src/v2/guide/installation.md
@@ -2,14 +2,18 @@
title: Installation
type: guide
order: 1
-vue_version: 2.5.16
-gz_size: "30.90"
+vue_version: 2.7.14
+gz_size: "37.51"
---
### Compatibility Note
Vue does **not** support IE8 and below, because it uses ECMAScript 5 features that are un-shimmable in IE8. However it supports all [ECMAScript 5 compliant browsers](https://caniuse.com/#feat=es5).
+### Semantic Versioning
+
+Vue follows [Semantic Versioning](https://semver.org/) in all its official projects for documented features and behavior. For undocumented behavior or exposed internals, changes are described in [release notes](https://github.com/vuejs/vue/releases).
+
### Release Notes
Latest stable version: {{vue_version}}
@@ -37,20 +41,20 @@ Simply download and include with a script tag. `Vue` will be registered as a glo
For prototyping or learning purposes, you can use the latest version with:
``` html
-
+
```
For production, we recommend linking to a specific version number and build to avoid unexpected breakage from newer versions:
``` html
-
+
```
If you are using native ES Modules, there is also an ES Modules compatible build:
``` html
```
@@ -67,7 +71,7 @@ NPM is the recommended installation method when building large scale application
``` bash
# latest stable
-$ npm install vue
+$ npm install vue@^2
```
## CLI
@@ -76,11 +80,11 @@ Vue provides an [official CLI](https://github.com/vuejs/vue-cli) for quickly sca
The CLI assumes prior knowledge of Node.js and the associated build tools. If you are new to Vue or front-end build tools, we strongly suggest going through the guide without any build tools before using the CLI.
-
+
## Explanation of Different Builds
-In the [`dist/` directory of the NPM package](https://cdn.jsdelivr.net/npm/vue/dist/) you will find many different builds of Vue.js. Here's an overview of the difference between them:
+In the [`dist/` directory of the NPM package](https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/) you will find many different builds of Vue.js. Here's an overview of the difference between them:
| | UMD | CommonJS | ES Module (for bundlers) | ES Module (for browsers) |
| --- | --- | --- | --- | --- |
@@ -97,7 +101,7 @@ In the [`dist/` directory of the NPM package](https://cdn.jsdelivr.net/npm/vue/d
- **Runtime**: code that is responsible for creating Vue instances, rendering and patching virtual DOM, etc. Basically everything minus the compiler.
-- **[UMD](https://github.com/umdjs/umd)**: UMD builds can be used directly in the browser via a `
+
## Creating a Vue Instance
Every Vue application starts by creating a new **Vue instance** with the `Vue` function:
@@ -24,10 +32,10 @@ A Vue application consists of a **root Vue instance** created with `new Vue`, op
Root Instance
└─ TodoList
├─ TodoItem
- │ ├─ DeleteTodoButton
- │ └─ EditTodoButton
+ │ ├─ TodoButtonDelete
+ │ └─ TodoButtonEdit
└─ TodoListFooter
- ├─ ClearTodosButton
+ ├─ TodosButtonClear
└─ TodoListStatistics
```
@@ -123,6 +131,8 @@ In the future, you can consult the [API reference](../api/#Instance-Properties)
## Instance Lifecycle Hooks
+
+
Each Vue instance goes through a series of initialization steps when it's created - for example, it needs to set up data observation, compile the template, mount the instance to the DOM, and update the DOM when data changes. Along the way, it also runs functions called **lifecycle hooks**, giving users the opportunity to add their own code at specific stages.
For example, the [`created`](../api/#created) hook can be used to run code after an instance is created:
diff --git a/src/v2/guide/join.md b/src/v2/guide/join.md
index d96506946a..c87118f707 100644
--- a/src/v2/guide/join.md
+++ b/src/v2/guide/join.md
@@ -49,11 +49,11 @@ Apart from answering questions and sharing resources in the forum and chat, ther
### Translate Docs
-Vue has already spread across the globe, with even the core team in at least half a dozen timezones. [The forum](https://forum.vuejs.org/) includes 7 languages and counting and many of our docs have [actively-maintained translations](https://github.com/vuejs?utf8=%E2%9C%93&query=vuejs.org). We're very proud of Vue's international reach, but we can do even better.
+Vue has already spread across the globe, with even the core team in at least half a dozen timezones. [The forum](https://forum.vuejs.org/) includes 7 languages and counting and many of our docs have [actively-maintained translations](https://github.com/vuejs?utf8=%E2%9C%93&q=vuejs.org). We're very proud of Vue's international reach, but we can do even better.
I hope that right now, you're reading this sentence in your preferred language. If not, would you like to help us get there?
-If so, please feel free to fork the repo for [these docs](https://github.com/vuejs/vuejs.org/) or for any other officially maintained documentation, then start translating. Once you've made some progress, open an issue or pull request in the main repo and we'll put out a call for more contributors to help you out.
+If so, please feel free to fork the repo for [these docs](https://github.com/vuejs/v2.vuejs.org/) or for any other officially maintained documentation, then start translating. Once you've made some progress, open an issue or pull request in the main repo and we'll put out a call for more contributors to help you out.
### Become a Community Leader
diff --git a/src/v2/guide/list.md b/src/v2/guide/list.md
index f79f833fc6..7701645894 100644
--- a/src/v2/guide/list.md
+++ b/src/v2/guide/list.md
@@ -4,13 +4,16 @@ type: guide
order: 8
---
+
+
+
## Mapping an Array to Elements with `v-for`
We can use the `v-for` directive to render a list of items based on an array. The `v-for` directive requires a special syntax in the form of `item in items`, where `items` is the source data array and `item` is an **alias** for the array element being iterated on:
``` html
@@ -32,7 +35,7 @@ Result:
{% raw %}
@@ -225,7 +228,7 @@ Since it's a generic mechanism for Vue to identify nodes, the `key` also has oth
Don't use non-primitive values like objects and arrays as `v-for` keys. Use string or numeric values instead.
-For detailed usage of the `key` attribute, please see the [`key` API documentation](https://vuejs.org/v2/api/#key).
+For detailed usage of the `key` attribute, please see the [`key` API documentation](/v2/api/#key).
## Array Change Detection
@@ -257,103 +260,7 @@ You might think this will cause Vue to throw away the existing DOM and re-render
### Caveats
-Due to limitations in JavaScript, Vue **cannot** detect the following changes to an array:
-
-1. When you directly set an item with the index, e.g. `vm.items[indexOfItem] = newValue`
-2. When you modify the length of the array, e.g. `vm.items.length = newLength`
-
-For example:
-
-``` js
-var vm = new Vue({
- data: {
- items: ['a', 'b', 'c']
- }
-})
-vm.items[1] = 'x' // is NOT reactive
-vm.items.length = 2 // is NOT reactive
-```
-
-To overcome caveat 1, both of the following will accomplish the same as `vm.items[indexOfItem] = newValue`, but will also trigger state updates in the reactivity system:
-
-``` js
-// Vue.set
-Vue.set(vm.items, indexOfItem, newValue)
-```
-``` js
-// Array.prototype.splice
-vm.items.splice(indexOfItem, 1, newValue)
-```
-
-You can also use the [`vm.$set`](https://vuejs.org/v2/api/#vm-set) instance method, which is an alias for the global `Vue.set`:
-
-``` js
-vm.$set(vm.items, indexOfItem, newValue)
-```
-
-To deal with caveat 2, you can use `splice`:
-
-``` js
-vm.items.splice(newLength)
-```
-
-## Object Change Detection Caveats
-
-Again due to limitations of modern JavaScript, **Vue cannot detect property addition or deletion**. For example:
-
-``` js
-var vm = new Vue({
- data: {
- a: 1
- }
-})
-// `vm.a` is now reactive
-
-vm.b = 2
-// `vm.b` is NOT reactive
-```
-
-Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it's possible to add reactive properties to a nested object using the `Vue.set(object, propertyName, value)` method. For example, given:
-
-``` js
-var vm = new Vue({
- data: {
- userProfile: {
- name: 'Anika'
- }
- }
-})
-```
-
-You could add a new `age` property to the nested `userProfile` object with:
-
-``` js
-Vue.set(vm.userProfile, 'age', 27)
-```
-
-You can also use the `vm.$set` instance method, which is an alias for the global `Vue.set`:
-
-``` js
-vm.$set(vm.userProfile, 'age', 27)
-```
-
-Sometimes you may want to assign a number of new properties to an existing object, for example using `Object.assign()` or `_.extend()`. In such cases, you should create a fresh object with properties from both objects. So instead of:
-
-``` js
-Object.assign(vm.userProfile, {
- age: 27,
- favoriteColor: 'Vue Green'
-})
-```
-
-You would add new, reactive properties with:
-
-``` js
-vm.userProfile = Object.assign({}, vm.userProfile, {
- age: 27,
- favoriteColor: 'Vue Green'
-})
-```
+Due to limitations in JavaScript, there are types of changes that Vue **cannot detect** with arrays and objects. These are discussed in the [reactivity](reactivity.html#Change-Detection-Caveats) section.
## Displaying Filtered/Sorted Results
@@ -380,13 +287,15 @@ computed: {
In situations where computed properties are not feasible (e.g. inside nested `v-for` loops), you can use a method:
-``` html
-{{ n }}
+```html
+
```
-``` js
+```js
data: {
- numbers: [ 1, 2, 3, 4, 5 ]
+ sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
diff --git a/src/v2/guide/migration-vue-2-7.md b/src/v2/guide/migration-vue-2-7.md
new file mode 100644
index 0000000000..9ab267bd29
--- /dev/null
+++ b/src/v2/guide/migration-vue-2-7.md
@@ -0,0 +1,120 @@
+---
+title: Migration to Vue 2.7
+type: guide
+order: 704
+---
+
+Vue 2.7 is the latest minor version of Vue 2. It provides built-in support for the [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html#composition-api-faq).
+
+Despite Vue 3 now being the default version, we understand that there are still many users who have to stay on Vue 2 due to dependency compatibility, browser support requirements, or simply not enough bandwidth to upgrade. In Vue 2.7, we have backported some of the most important features from Vue 3 so that Vue 2 users can benefit from them as well.
+
+## Backported Features
+
+- [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)
+- SFC [`
-{% endraw %}
+
diff --git a/src/v2/guide/security.md b/src/v2/guide/security.md
new file mode 100644
index 0000000000..f0877d106c
--- /dev/null
+++ b/src/v2/guide/security.md
@@ -0,0 +1,185 @@
+---
+title: Security
+type: guide
+order: 504
+---
+
+## Reporting Vulnerabilities
+
+When a vulnerability is reported, it immediately becomes our top concern, with a full-time contributor dropping everything to work on it. To report a vulnerability, please email [security@vuejs.org](mailto:security@vuejs.org).
+
+While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
+
+## Rule No.1: Never Use Non-trusted Templates
+
+The most fundamental security rule when using Vue is **never use non-trusted content as your component template**. Doing so is equivalent to allowing arbitrary JavaScript execution in your application - and worse, could lead to server breaches if the code is executed during server-side rendering. An example of such usage:
+
+``` js
+new Vue({
+ el: '#app',
+ template: `` + userProvidedString + `
` // NEVER DO THIS
+})
+```
+
+Vue templates are compiled into JavaScript, and expressions inside templates will be executed as part of the rendering process. Although the expressions are evaluated against a specific rendering context, due to the complexity of potential global execution environments, it is impractical for a framework like Vue to completely shield you from potential malicious code execution without incurring unrealistic performance overhead. The most straightforward way to avoid this category of problems altogether is to make sure the contents of your Vue templates are always trusted and entirely controlled by you.
+
+## What Vue Does to Protect You
+
+### HTML content
+
+Whether using templates or render functions, content is automatically escaped. That means in this template:
+
+```html
+{{ userProvidedString }}
+```
+
+if `userProvidedString` contained:
+
+```js
+''
+```
+
+then it would be escaped to the following HTML:
+
+```html
+<script>alert("hi")</script>
+```
+
+thus preventing the script injection. This escaping is done using native browser APIs, like `textContent`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+### Attribute bindings
+
+Similarly, dynamic attribute bindings are also automatically escaped. That means in this template:
+
+```html
+
+ hello
+
+```
+
+if `userProvidedString` contained:
+
+```js
+'" onclick="alert(\'hi\')'
+```
+
+then it would be escaped to the following HTML:
+
+```html
+" onclick="alert('hi')
+```
+
+thus preventing the close of the `title` attribute to inject new, arbitrary HTML. This escaping is done using native browser APIs, like `setAttribute`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+## Potential Dangers
+
+In any web application, allowing unsanitized, user-provided content to be executed as HTML, CSS, or JavaScript is potentially dangerous, so should be avoided wherever possible. There are times when some risk be acceptable though.
+
+For example, services like CodePen and JSFiddle allow user-provided content to be executed, but it's in a context where this is expected and sandboxed to some extent inside iframes. In the cases when an important feature inherently requires some level of vulnerability, it's up to your team to weigh the importance of the feature against the worst-case scenarios the vulnerability enables.
+
+### Injecting HTML
+
+As you learned earlier, Vue automatically escapes HTML content, preventing you from accidentally injecting executable HTML into your application. However, in cases where you know the HTML is safe, you can explicitly render HTML content:
+
+- Using a template:
+ ```html
+
+ ```
+
+- Using a render function:
+ ```js
+ h('div', {
+ domProps: {
+ innerHTML: this.userProvidedHtml
+ }
+ })
+ ```
+
+- Using a render function with JSX:
+ ```jsx
+
+ ```
+
+Note that user-provided HTML can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that HTML can ever be exposed to it. Additionally, allowing users to write their own Vue templates brings similar dangers.
+
+### Injecting URLs
+
+In a URL like this:
+
+```html
+
+ click me
+
+```
+
+There's a potential security issue if the URL has not been "sanitized" to prevent JavaScript execution using `javascript:`. There are libraries such as [sanitize-url](https://www.npmjs.com/package/@braintree/sanitize-url) to help with this, but note:
+
+If you're ever doing URL sanitization on the frontend, you already have a security issue. User-provided URLs should always be sanitized by your backend before even being saved to a database. Then the problem is avoided for _every_ client connecting to your API, including native mobile apps. Also note that even with sanitized URLs, Vue cannot help you guarantee that they lead to safe destinations.
+
+### Injecting Styles
+
+Looking at this example:
+
+```html
+
+ click me
+
+```
+
+let's assume that `sanitizedUrl` has been sanitized, so that it's definitely a real URL and not JavaScript. With the `userProvidedStyles`, malicious users could still provide CSS to "click jack", e.g. styling the link into a transparent box over the "Log in" button. Then if `https://user-controlled-website.com/` is built to resemble the login page of your application, they might have just captured a user's real login information.
+
+You may be able to imagine how allowing user-provided content for a `
+```
+
+To keep your users fully safe from click jacking, we recommend only allowing full control over CSS inside a sandboxed iframe. Alternatively, when providing user control through a style binding, we recommend using its [object syntax](class-and-style.html#Object-Syntax-1) and only allowing users to provide values for specific properties it's safe for them to control, like this:
+
+```html
+
+ click me
+
+```
+
+### Injecting JavaScript
+
+We strongly discourage ever rendering a `
+
{% endraw %}
diff --git a/src/v2/guide/testing.md b/src/v2/guide/testing.md
new file mode 100644
index 0000000000..bda896238f
--- /dev/null
+++ b/src/v2/guide/testing.md
@@ -0,0 +1,168 @@
+---
+title: Testing
+type: guide
+order: 402
+---
+
+## Introduction
+
+When it comes to building reliable applications, tests can play a critical role in an individual or team's ability to build new features, refactor code, fix bugs, etc. While there are many schools of thought with testing, there are three categories often discussed in the context of web applications:
+
+- Unit Testing
+- Component Testing
+- End-To-End (E2E) Testing
+
+This section aims to provide guidance to navigating the testing ecosystem and choosing the right tools for your Vue application or component library.
+
+## Unit Testing
+
+### Introduction
+
+Unit tests allow you to test individual units of code in isolation. The purpose of unit testing is to provide developers with confidence in their code. By writing thorough, meaningful tests, you achieve the confidence that as new features are built or your code is refactored your application will remain functional and stable.
+
+Unit testing a Vue application does not significantly differ from testing other types of applications.
+
+### Choosing Your Framework
+
+Since unit testing advice is often framework-agnostic, here are some basic guidelines to keep in mind when evaluating which unit testing tool is best for your application.
+
+#### First-class error reporting
+
+When tests fail, it is critical that your unit testing framework provides useful errors. This is the job of the assertion library. An assertion with high-quality error messages helps minimize the amount of time it takes to debug the problem. In addition to simply telling you what test is failing, assertion libraries provide context for why a test fails, e.g., what is expected vs what was received.
+
+Some unit testing frameworks, like Jest, include assertion libraries. Others, like Mocha, require you to install assertion libraries separately (usually Chai).
+
+#### Active community and team
+
+Since the majority of unit testing frameworks are open-source, having a community that is active can be critical to some teams that will be maintaining their tests for a long period of time and needs to ensure that a project will be actively maintained. In addition, having an active community has the benefit of providing more support whenever you run into issues.
+
+### Frameworks
+
+While there are many tools in the ecosystem, here are some common unit testing tools that are being used in the Vue.js ecosystem.
+
+#### Jest
+
+Jest is a JavaScript test framework that is focused on simplicity. One of its unique features is the ability to take snapshots of tests in order to provide an alternative means of verifying units of your application.
+
+**Resources:**
+
+- [Official Jest Website](https://jestjs.io)
+- [Official Vue 2 CLI Plugin - Jest](https://cli.vuejs.org/core-plugins/unit-jest.html)
+
+#### Mocha
+
+Mocha is a JavaScript test framework that is focused on being flexible. Because of this flexibility, it allows you to choose different libraries to fulfill other common features such as spying (e.g., Sinon) and assertions (e.g., Chai). Another unique feature of Mocha is that it can also execute tests in the browser in addition to Node.js.
+
+**Resources:**
+
+- [Official Mocha Website](https://mochajs.org)
+- [Official Vue CLI Plugin - Mocha](https://cli.vuejs.org/core-plugins/unit-mocha.html)
+
+## Component Testing
+
+### Introduction
+
+To test most Vue components, they must be mounted to the DOM (either virtual or real) in order to fully assert that they are working. This is another framework-agnostic concept. As a result, component testing frameworks were created to give users the ability to do this reliably while also providing Vue-specific conveniences such as integrations for Vuex, Vue Router, and other Vue plugins.
+
+### Choosing Your Framework
+
+The following section provides guidelines on things to keep in mind when evaluating which component testing framework is best for your application.
+
+#### Optimal compatibility with the Vue ecosystem
+
+It should be no surprise that one of the first criteria is that a component testing library should have is being as compatible with the Vue ecosystem as possible. While this may seem comprehensive, some key integration areas to keep in mind include single file components (SFCs), Vuex, Vue Router, and any other Vue specific plugins that your application relies on.
+
+#### First-class error reporting
+
+When tests fail, it is critical that your component testing framework provides useful error logs that help to minimize the amount of time it takes to debug the problem. In addition to simply telling you what test fails, they should also provide context for why a test fails, e.g., what is expected vs what was received.
+
+### Recommendations
+
+#### Vue Testing Library (@testing-library/vue)
+
+Vue Testing Library is a set of tools focused on testing components without relying on implementation details. Built with accessibility in mind, its approach also makes refactoring a breeze.
+
+Its guiding principle is that the more tests resemble the way software is used, the more confidence they can provide.
+
+**Resources:**
+
+- [Official Vue Testing Library Website](https://testing-library.com/docs/vue-testing-library/intro)
+
+#### Vue Test Utils
+
+Vue Test Utils is the official low-level component testing library that was written to provide users access to Vue specific APIs. If you are new to testing Vue applications, we would recommend using Vue Testing Library, which is an abstraction over Vue Test Utils.
+
+**Resources**
+
+- [Official Vue Test Utils Documentation](https://vue-test-utils.vuejs.org)
+- [Vue Testing Handbook](https://lmiller1990.github.io/vue-testing-handbook/#what-is-this-guide) by Lachlan Miller
+- [Cookbook: Unit Testing Vue Components](/v2/cookbook/unit-testing-vue-components.html)
+
+## End-to-End (E2E) Testing
+
+### Introduction
+
+While unit tests provide developers with some degree of confidence, unit and component tests are limited in their abilities to provide holistic coverage of an application when deployed to production. As a result, end-to-end (E2E) tests provide coverage on what is arguably the most important aspect of an application: what happens when users actually use your applications.
+
+In other words, E2E tests validate all of the layers in your application. This not only includes your frontend code, but all associated backend services and infrastructure that are more representative of the environment that your users will be in. By testing how user actions impact your application, E2E tests are often the key to higher confidence in whether an application is functioning properly or not.
+
+### Choosing Your Framework
+
+While end-to-end (E2E) testing on the web has gained a negative reputation for unreliable (flaky) tests and slowing down development processes, modern E2E tools have made strides forward to create more reliable, interactive, and useful tests. When choosing an E2E testing framework, the following sections provide some guidance on things to keep in mind when choosing a testing framework for your application.
+
+#### Cross-browser testing
+
+One of the primary benefits that end-to-end (E2E) testing is known for is its ability to test your application across multiple browsers. While it may seem desirable to have 100% cross-browser coverage, it is important to note that cross browser testing has diminishing returns on a team's resources due the additional time and machine power required to run them consistently. As a result, it is important to be mindful of this trade-off when choosing the amount of cross-browser testing your application needs.
+
+A recent development in E2E for catching browser-specific issues is using application monitoring and error reporting tools (e.g., Sentry, LogRocket, etc.) for browsers that are not as commonly used (e.g., < IE11, older Safari versions, etc.).
+
+#### Faster feedback loops
+
+One of the primary problems with end-to-end (E2E) tests and development is that running the entire suite takes a long time. Typically, this is only done in continuous integration and deployment (CI/CD) pipelines. Modern E2E testing frameworks have helped to solve this by adding features like parallelization, which allows for CI/CD pipelines to often run magnitudes faster than before. In addition, when developing locally, the ability to selectively run a single test for the page you are working on while also providing hot reloading of tests can help to boost a developer's workflow and productivity.
+
+#### First class debugging experience
+
+While developers have traditionally relied on scanning logs in a terminal window to help determine what went wrong in a test, modern end-to-end (E2E) test frameworks allow developers to leverage tools that they are already familiar with, e.g. browser developer tools.
+
+#### Visibility in headless mode
+
+When end-to-end (E2E) tests are run in continuous integration / deployment pipelines, they are often run in headless browsers (i.e., no visible browser is opened for the user to watch). As a result, when errors occur, a critical feature that modern E2E testing frameworks provide 1st class support for is the ability to see snapshots and/or videos of your applications during various testing stages in order to provide insight into why errors are happening. Historically, it was tedious to maintain these integrations.
+
+### Recommendations
+
+While there are many tools in the ecosystem, here are some common end-to-end (E2E) testing frameworks that are being used in the Vue.js ecosystem.
+
+#### Cypress.io
+
+Cypress.io is a testing framework that aims to enhance developer productivity by enabling developers to reliably test their applications while providing a first class developer experience.
+
+**Resources**
+
+- [Cypress' Official Website](https://www.cypress.io)
+- [Official Vue CLI Cypress Plugin](https://cli.vuejs.org/core-plugins/e2e-cypress.html)
+- [Cypress Testing Library](https://github.com/testing-library/cypress-testing-library)
+
+#### Nightwatch.js
+
+Nightwatch.js is an end-to-end testing framework that can be used to test web applications and websites, as well as Node.js unit and integration testing.
+
+**Resources:**
+
+- [Nightwatch's Official Website](https://nightwatchjs.org)
+- [Official Vue CLI Nightwatch Plugin](https://cli.vuejs.org/core-plugins/e2e-nightwatch.html)
+
+#### Puppeteer
+
+Puppeteer is a Node library that provides a high-level API to control the browser and can pair with other test runners (e.g., Jest) to test your application.
+
+**Resources:**
+
+- [Puppeteer's Official Website](https://pptr.dev)
+
+#### TestCafe
+
+TestCafe is a Node.js based end-to-end framework that aims to provide easy setup so that developers can focus on creating tests that are easy to write and reliable.
+
+**Resources:**
+
+- [TestCafe's Official Website](https://devexpress.github.io/testcafe/)
diff --git a/src/v2/guide/transitioning-state.md b/src/v2/guide/transitioning-state.md
index d9cc1ca97e..dd0bf5a50b 100644
--- a/src/v2/guide/transitioning-state.md
+++ b/src/v2/guide/transitioning-state.md
@@ -18,7 +18,7 @@ All of these are either already stored as raw numbers or can be converted into n
Watchers allow us to animate changes of any numerical property into another property. That may sound complicated in the abstract, so let's dive into an example using [GreenSock](https://greensock.com/):
``` html
-
+
@@ -40,14 +40,14 @@ new Vue({
},
watch: {
number: function(newValue) {
- TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
+ gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
}
}
})
```
{% raw %}
-
+
{{ animatedNumber }}
@@ -66,7 +66,7 @@ new Vue({
},
watch: {
number: function(newValue) {
- TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
+ gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
}
}
})
@@ -366,7 +366,7 @@ function generatePoints (stats) {
{% endraw %}
-See [this fiddle](https://jsfiddle.net/chrisvfritz/65gLu2b6/) for the complete code behind the above demo.
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-state-transitions) for the complete code behind the above demo.
## Organizing Transitions into Components
diff --git a/src/v2/guide/transitions.md b/src/v2/guide/transitions.md
index b1b91c2d4c..7f0637d78e 100644
--- a/src/v2/guide/transitions.md
+++ b/src/v2/guide/transitions.md
@@ -4,6 +4,12 @@ type: guide
order: 201
---
+
+
## Overview
Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM. This includes tools to:
@@ -479,6 +485,7 @@ new Vue({
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
+ el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
@@ -959,6 +966,7 @@ So what about for when we have a whole list of items we want to render simultane
- Unlike `
`, it renders an actual element: a `` by default. You can change the element that's rendered with the `tag` attribute.
- [Transition modes](#Transition-Modes) are not available, because we are no longer alternating between mutually exclusive elements.
- Elements inside are **always required** to have a unique `key` attribute.
+- CSS transition classes will be applied to inner elements and not to the group/container itself.
### List Entering/Leaving Transitions
@@ -1243,7 +1251,7 @@ new Vue({
One important note is that these FLIP transitions do not work with elements set to `display: inline`. As an alternative, you can use `display: inline-block` or place elements in a flex context.
-These FLIP animations are also not limited to a single axis. Items in a multidimensional grid can be [transitioned too](https://jsfiddle.net/chrisvfritz/sLrhk1bc/):
+These FLIP animations are also not limited to a single axis. Items in a multidimensional grid can be [transitioned too](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-list-move-transitions):
{% raw %}
diff --git a/src/v2/guide/typescript.md b/src/v2/guide/typescript.md
index 8922bfea44..19d01a87d0 100644
--- a/src/v2/guide/typescript.md
+++ b/src/v2/guide/typescript.md
@@ -4,13 +4,13 @@ type: guide
order: 403
---
-> [Vue CLI](https://cli.vuejs.org) provides built-in TypeScript tooling support.
+> [Vue CLI](https://cli.vuejs.org) provides built-in TypeScript tooling support.
## Official Declaration in NPM Packages
A static type system can help prevent many potential runtime errors, especially as applications grow. That's why Vue ships with [official type declarations](https://github.com/vuejs/vue/tree/dev/types) for [TypeScript](https://www.typescriptlang.org/) - not only in Vue core, but also for [vue-router](https://github.com/vuejs/vue-router/tree/dev/types) and [vuex](https://github.com/vuejs/vuex/tree/dev/types) as well.
-Since these are [published on NPM](https://cdn.jsdelivr.net/npm/vue/types/), and the latest TypeScript knows how to resolve type declarations in NPM packages, this means when installed via NPM, you don't need any additional tooling to use TypeScript with Vue.
+Since these are [published on NPM](https://cdn.jsdelivr.net/npm/vue@2/types/), and the latest TypeScript knows how to resolve type declarations in NPM packages, this means when installed via NPM, you don't need any additional tooling to use TypeScript with Vue.
## Recommended Configuration
@@ -187,3 +187,34 @@ const Component = Vue.extend({
```
If you find type inference or member completion isn't working, annotating certain methods may help address these problems. Using the `--noImplicitAny` option will help find many of these unannotated methods.
+
+
+
+## Annotating Props
+
+```ts
+import Vue, { PropType } from 'vue'
+
+interface ComplexMessage {
+ title: string,
+ okMessage: string,
+ cancelMessage: string
+}
+const Component = Vue.extend({
+ props: {
+ name: String,
+ success: { type: String },
+ callback: {
+ type: Function as PropType<() => void>
+ },
+ message: {
+ type: Object as PropType
,
+ required: true,
+ validator (message: ComplexMessage) {
+ return !!message.title;
+ }
+ }
+ }
+})
+```
+If you find validator not getting type inference or member completion isn't working, annotating the argument with the expected type may help address these problems.
diff --git a/src/v2/guide/unit-testing.md b/src/v2/guide/unit-testing.md
deleted file mode 100644
index b3c8c9ff88..0000000000
--- a/src/v2/guide/unit-testing.md
+++ /dev/null
@@ -1,130 +0,0 @@
----
-title: Unit Testing
-type: guide
-order: 402
----
-
-> [Vue CLI](https://cli.vuejs.org/) has built-in options for unit testing with [Jest](https://github.com/facebook/jest) or [Mocha](https://mochajs.org/) that works out of the box. We also have the official [Vue Test Utils](https://vue-test-utils.vuejs.org/) which provides more detailed guidance for custom setups.
-
-## Simple Assertions
-
-You don't have to do anything special in your components to make them testable. Export the raw options:
-
-``` html
-
- {{ message }}
-
-
-
-```
-
-Then import the component options along with Vue, and you can make many common assertions (here we are using Jasmine/Jest style `expect` assertions just as an example):
-
-``` js
-// Import Vue and the component being tested
-import Vue from 'vue'
-import MyComponent from 'path/to/MyComponent.vue'
-
-// Here are some Jasmine 2.0 tests, though you can
-// use any test runner / assertion library combo you prefer
-describe('MyComponent', () => {
- // Inspect the raw component options
- it('has a created hook', () => {
- expect(typeof MyComponent.created).toBe('function')
- })
-
- // Evaluate the results of functions in
- // the raw component options
- it('sets the correct default data', () => {
- expect(typeof MyComponent.data).toBe('function')
- const defaultData = MyComponent.data()
- expect(defaultData.message).toBe('hello!')
- })
-
- // Inspect the component instance on mount
- it('correctly sets the message when created', () => {
- const vm = new Vue(MyComponent).$mount()
- expect(vm.message).toBe('bye!')
- })
-
- // Mount an instance and inspect the render output
- it('renders the correct message', () => {
- const Constructor = Vue.extend(MyComponent)
- const vm = new Constructor().$mount()
- expect(vm.$el.textContent).toBe('bye!')
- })
-})
-```
-
-## Writing Testable Components
-
-A component's render output is primarily determined by the props it receives. If a component's render output solely depends on its props it becomes straightforward to test, similar to asserting the return value of a pure function with different arguments. Take a simplified example:
-
-``` html
-
- {{ msg }}
-
-
-
-```
-
-You can assert its render output with different props using the `propsData` option:
-
-``` js
-import Vue from 'vue'
-import MyComponent from './MyComponent.vue'
-
-// helper function that mounts and returns the rendered text
-function getRenderedText (Component, propsData) {
- const Constructor = Vue.extend(Component)
- const vm = new Constructor({ propsData: propsData }).$mount()
- return vm.$el.textContent
-}
-
-describe('MyComponent', () => {
- it('renders correctly with different props', () => {
- expect(getRenderedText(MyComponent, {
- msg: 'Hello'
- })).toBe('Hello')
-
- expect(getRenderedText(MyComponent, {
- msg: 'Bye'
- })).toBe('Bye')
- })
-})
-```
-
-## Asserting Asynchronous Updates
-
-Since Vue [performs DOM updates asynchronously](reactivity.html#Async-Update-Queue), assertions on DOM updates resulting from state change will have to be made in a `Vue.nextTick` callback:
-
-``` js
-// Inspect the generated HTML after a state update
-it('updates the rendered message when vm.message updates', done => {
- const vm = new Vue(MyComponent).$mount()
- vm.message = 'foo'
-
- // wait a "tick" after state change before asserting DOM updates
- Vue.nextTick(() => {
- expect(vm.$el.textContent).toBe('foo')
- done()
- })
-})
-```
-
-For more in-depth information on unit testing in Vue, check out [Vue Test Utils](https://vue-test-utils.vuejs.org/) and our cookbook entry about [unit testing vue components](https://vuejs.org/v2/cookbook/unit-testing-vue-components.html).
diff --git a/src/v2/style-guide/index.md b/src/v2/style-guide/index.md
index 5ca7bb4466..8567e99b66 100644
--- a/src/v2/style-guide/index.md
+++ b/src/v2/style-guide/index.md
@@ -45,7 +45,7 @@ Some features of Vue exist to accommodate rare edge cases or smoother migrations
**Component names should always be multi-word, except for root `App` components, and built-in components provided by Vue, such as `` or ``.**
-This [prevents conflicts](http://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word.
+This [prevents conflicts](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word.
{% raw %}{% endraw %}
#### Bad
@@ -189,7 +189,7 @@ In committed code, prop definitions should always be as detailed as possible, sp
{% endraw %}
-Detailed [prop definitions](https://vuejs.org/v2/guide/components.html#Prop-Validation) have two advantages:
+Detailed [prop definitions](/v2/guide/components.html#Prop-Validation) have two advantages:
- They document the API of the component, so that it's easy to see how the component is meant to be used.
- In development, Vue will warn you if a component is ever provided incorrectly formatted props, helping you catch potential sources of error.
@@ -771,22 +771,6 @@ Some advantages of this convention:
- Since component names should always be multi-word, this convention prevents you from having to choose an arbitrary prefix for simple component wrappers (e.g. `MyButton`, `VueButton`).
-- Since these components are so frequently used, you may want to simply make them global instead of importing them everywhere. A prefix makes this possible with Webpack:
-
- ``` js
- var requireComponent = require.context("./src", true, /^Base[A-Z]/)
- requireComponent.keys().forEach(function (fileName) {
- var baseComponentConfig = requireComponent(fileName)
- baseComponentConfig = baseComponentConfig.default || baseComponentConfig
- var baseComponentName = baseComponentConfig.name || (
- fileName
- .replace(/^.+\//, '')
- .replace(/\.\w+$/, '')
- )
- Vue.component(baseComponentName, baseComponentConfig)
- })
- ```
-
{% raw %}{% endraw %}
{% raw %}
{% endraw %}
@@ -1353,7 +1337,7 @@ Simpler, well-named computed properties are:
- __Easier to read__
- Simplifying computed properties forces you to give each value a descriptive name, even if it's not reused. This makes it much easier for other developers (and future you) to focus in on the code they care about and figure out what's going on.
+ Simplifying computed properties forces you to give each value a descriptive name, even if it's not reused. This makes it much easier for other developers (and future you) to focus on the code they care about and figure out what's going on.
- __More adaptable to changing requirements__
@@ -1454,7 +1438,7 @@ While attribute values without any spaces are not required to have quotes in HTM
``` html
- Here might be a page title
+ Here might be a page title
@@ -1496,7 +1480,7 @@ While attribute values without any spaces are not required to have quotes in HTM
``` html
- Here might be a page title
+ Here might be a page title
@@ -1506,7 +1490,7 @@ While attribute values without any spaces are not required to have quotes in HTM
``` html
- Here might be a page title
+ Here might be a page title
@@ -1612,7 +1596,6 @@ This is the default order we recommend for component options. They're split into
6. **Unique Attributes** (attributes that require unique values)
- `ref`
- `key`
- - `slot`
7. **Two-Way Binding** (combining binding and events)
- `v-model`
@@ -1756,7 +1739,7 @@ computed: {
**It's usually best to use `key` with `v-if` + `v-else`, if they are the same element type (e.g. both `` elements).**
-By default, Vue updates the DOM as efficiently as possible. That means when switching between elements of the same type, it simply patches the existing element, rather than removing it and adding a new one in its place. This can have [unintended consequences](https://jsfiddle.net/chrisvfritz/bh8fLeds/) if these elements should not actually be considered the same.
+By default, Vue updates the DOM as efficiently as possible. That means when switching between elements of the same type, it simply patches the existing element, rather than removing it and adding a new one in its place. This can have [unintended consequences](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-priority-d-rules-unintended-consequences) if these elements should not actually be considered the same.
{% raw %}
{% endraw %}
#### Bad
@@ -1807,7 +1790,7 @@ Prefer class selectors over element selectors in `scoped` styles, because large
To scope styles, Vue adds a unique attribute to component elements, such as `data-v-f3f3eg9`. Then selectors are modified so that only matching elements with this attribute are selected (e.g. `button[data-v-f3f3eg9]`).
-The problem is that large numbers of [element-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=a%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than [class-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=.class%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
+The problem is that large numbers of element-attribute selectors (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than class-attribute selectors (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
{% raw %}{% endraw %}
@@ -1942,7 +1925,9 @@ Vue.component('TodoItem', {
**[Vuex](https://github.com/vuejs/vuex) should be preferred for global state management, instead of `this.$root` or a global event bus.**
-Managing state on `this.$root` and/or using a [global event bus](https://vuejs.org/v2/guide/migration.html#dispatch-and-broadcast-replaced) can be convenient for very simple cases, but are not appropriate for most applications. Vuex offers not only a central place to manage state, but also tools for organizing, tracking, and debugging state changes.
+Managing state on `this.$root` and/or using a [global event bus](/v2/guide/migration.html#dispatch-and-broadcast-replaced) can be convenient for very simple cases, but it is not appropriate for most applications.
+
+Vuex is the [official flux-like implementation](/v2/guide/state-management.html#Official-Flux-Like-Implementation) for Vue, and offers not only a central place to manage state, but also tools for organizing, tracking, and debugging state changes. It integrates well in the Vue ecosystem (including full [Vue DevTools](/v2/guide/installation.html#Vue-Devtools) support).
{% raw %}{% endraw %}
diff --git a/themes/vue/_config.yml b/themes/vue/_config.yml
index 247cef49ee..ae2c91815a 100644
--- a/themes/vue/_config.yml
+++ b/themes/vue/_config.yml
@@ -1,131 +1,246 @@
site_description: Vue.js - The Progressive JavaScript Framework
google_analytics: UA-46852172-1
root_domain: vuejs.org
-vue_version: 2.5.16
-platinum_sponsors_china:
- - url: 'http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci='
- img: dcloud.gif
-special_sponsors:
- - url: 'https://stdlib.com/'
- img: stdlib.png
- description: 'Build APIs you need in minutes instead of days, for free.'
-platinum_sponsors:
- - url: >-
- https://bit.dev/?utm_source=vue&utm_medium=vue&utm_campaign=vue&utm_term=vue&utm_content=vue
- img: bit.png
- name: Bit
- - url: 'http://tooltwist.com/'
- img: tooltwist.png
- name: Tooltwist
- - url: >-
+vue_version: 2.7.14
+# START SPONSORS
+special:
+ - name: appwrite
+ url: https://appwrite.io
+ img: appwrite.svg
+ description: Open-source backend cloud platform
+ priority: true
+platinum:
+ - name: Bit
+ url: https://bit.dev
+ img: bit.svg?v2
+ priority: true
+ - name: VueMastery
+ url: https://www.vuemastery.com/
+ img: vuemastery.png
+ - name: VueSchool
+ url: >-
https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1
img: vueschool.png
- name: VueSchool
- - url: 'https://vehikl.com/'
+ - name: Vehikl
+ url: https://vehikl.com/
img: vehikl.png
- name: Vehikl
- - url: >-
- https://www.nativescript.org/vue?utm_source=vue-js-org&utm_medium=website&utm_campaign=nativescript-awareness
- img: nativescript.png
- name: NativeScript
-gold_sponsors:
- - url: 'https://www.vuemastery.com/'
- img: vuemastery.png
- name: VueMastery
- - url: 'https://laravel.com'
+ - name: Passionate People
+ url: https://passionatepeople.io/
+ img: passionate_people.png
+ - name: Storyblok
+ url: https://www.storyblok.com
+ img: storyblok.png
+ - name: Ionic
+ url: >-
+ https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs
+ img: ionic.png?v2
+ - name: Skilled
+ url: https://skilled.yashio-corp.com
+ img: skilled.svg
+ - name: Chrome Frameworks Fund
+ url: https://opencollective.com/2021-frameworks-fund
+ img: chrome_frameworks_fund.png
+ - name: HeroDevs
+ url: https://www.herodevs.com/support/vue
+ img: herodevs.png
+gold:
+ - name: Laravel
+ url: https://laravel.com
img: laravel.png
- name: Laravel
- - url: 'https://chaitin.cn/en/'
- img: chaitin.png
- name: Chaitin
- - url: 'https://htmlburger.com'
- img: html_burger.png
- name: HTML Burger
- - url: 'https://www.frontenddeveloperlove.com/'
- img: frontend_love.png
- name: Frontend Love
- - url: 'https://onsen.io/vue/'
- img: onsen_ui.png
- name: Onsen UI
- - url: 'https://neds.com.au/'
- img: neds.png
- name: Neds
- - url: 'https://icons8.com/'
- img: icons_8.png
- name: Icons 8
- - url: 'https://vuejobs.com/?ref=vuejs'
- img: vuejobs.png
- name: VueJobs
- - url: 'https://www.valuecoders.com'
- img: valuecoders.png
- name: ValueCoders
- - url: 'https://tidelift.com/subscription/npm/vue'
+ - name: Tidelift
+ url: https://tidelift.com/subscription/npm/vue
img: tidelift.png
- name: Tidelift
- - url: >-
- http://www.syncfusion.com/?utm_source=vuejs&utm_medium=list&utm_campaign=vuejsjslistcy19
- img: syncfusion.png
- name: SyncFusion
- - url: 'https://opteo.com/vue'
- img: opteo.png
- name: Opteo
- - url: 'https://devsquad.com/'
- img: devsquad.png
- name: DevSquad
- - url: 'https://www.firesticktricks.com/'
- img: firestick_tricks.png
- name: Firestick Tricks
- - url: 'https://intygrate.com/'
+ - name: Intygrate
+ url: https://intygrate.com/
img: intygrate.png
- name: Intygrate
- - url: 'https://isleofcode.com/'
- img: isle_of_code.png
- name: Isle of Code
- - url: 'https://passionatepeople.io/'
- img: passionate_people.png
- name: Passionate People
- - url: 'http://en.shopware.com/'
- img: shopware_ag.png
- name: shopware AG
- - url: >-
- https://x-team.com/join/?utm_source=vuejsorg&utm_medium=sponsor&utm_campaign=vuejsorg-patreon
- img: x_team.png
- name: X-Team
- - url: 'https://www.vpnranks.com/'
- img: vpnranks.png
- name: VPNRanks
- - url: 'https://www.simplyswitch.com/'
- img: energy_comparison.png
- name: Energy Comparison
- - url: 'https://www.bacancytechnology.com'
- img: bacancy_technology.png
- name: Bacancy Technology
- - url: 'https://blokt.com/'
- img: blokt_cryptocurrency_news.png
- name: Blokt Cryptocurrency News
- - url: 'https://www.jqwidgets.com/vue/'
- img: jqwidgets_ltd.png
- name: jQWidgets LTD
- - url: 'https://www.y8.com/'
+ - name: Y8
+ url: https://www.y8.com/
img: y8.png
- name: Y8
- - url: 'https://js.devexpress.com/'
+ - name: DevExpress
+ url: https://js.devexpress.com/
img: devexpress.png
- name: DevExpress
-silver_sponsors:
- - url: 'https://dopamine.bg/'
- img: dopamine.png
- name: Dopamine
-bronze_sponsors:
- - url: 'http://tighten.co/'
- img: tighten_co.png
- name: Tighten.co
- - url: 'https://www.accelebrate.com/'
- img: accelebrate.png
- name: Accelebrate
- - url: 'https://polyglotengineer.com/derek.pollard'
+ - name: FASTCODING Inc
+ url: 'https://fastcoding.jp/javascript/ '
+ img: fastcoding_inc.svg
+ - name: LY Corporation
+ url: https://www.lycorp.co.jp/en/
+ img: ly_corporation.png?v2
+ - name: Fenêtre Online Solutions
+ url: https://www.fenetre.nl/
+ img: fen_tre_online_solutions.svg
+ - name: Ant Design Vue
+ url: https://antdv.com
+ img: ant_design_vue.png
+ - name: Crisp
+ url: https://crisp.chat/en/
+ img: crisp.png
+ - name: Localazy
+ url: >-
+ https://localazy.com/blog/how-to-localize-vuejs-app-with-vue-i18n-and-localazy?utm_source=vuejs&utm_medium=banner&utm_campaign=sponsorships_vuejs&utm_content=logo
+ img: localazy.svg
+ - name: Casinoburst.com
+ url: https://casinoburst.com/casino-utan-licens/
+ img: casinoburst_com.png
+ - name: 'Enkrypt: Ethereum and Polkadot Web3 Wallet'
+ url: https://www.enkrypt.com
+ img: enkrypt__ethereum_and_polkadot_web3_wallet.svg
+ - name: uudetkasinot.com
+ url: https://www.uudetkasinot.com
+ img: uudetkasinot_com.png
+ - name: Fathom Analytics
+ url: https://usefathom.com/
+ img: fathom_analytics.svg
+ - name: Goread.io
+ url: https://goread.io/buy-instagram-followers
+ img: goread_io.png
+ - name: Sentry
+ url: https://sentry.io/for/vue?utm_source=vuejs.org&utm_medium=paid-community
+ img: sentry.png
+ - name: Poprey.com
+ url: https://poprey.com/
+ img: poprey_com.png
+ - name: Ilmaiset Pitkävetovihjeet
+ url: https://www.vedonlyontibonukset.com/pitkavetovihjeet
+ img: ilmaiset_pitk_vetovihjeet.png
+ - name: Famoid
+ url: https://famoid.com/
+ img: famoid.png
+ - name: Certible
+ url: https://www.certible.com
+ img: certible.svg
+ - name: FORTUNE GAMES
+ url: https://www.fortunegames.com
+ img: fortune_games.png
+ - name: TBDC - Agro Software
+ url: http://tbdc.com.br/
+ img: tbdc___agro_software.svg
+ - name: FineProxy
+ url: https://fineproxy.org/
+ img: fineproxy.svg
+ - name: Daniel
+ url: >-
+ https://rxdb.info/?utm_source=sponsor&utm_medium=opencollective&utm_campaign=opencollective-vuejs
+ img: daniel.png
+ - name: SurveyJS
+ url: https://surveyjs.io/
+ img: surveyjs.png?v2
+ - name: Stormlikes
+ url: https://www.stormlikes.net/buy-instagram-followers
+ img: stormlikes.png
+silver:
+ - name: Draxlr
+ url: https://www.draxlr.com
+ img: draxlr.svg
+ - name: Team Extension North America Inc
+ url: https://teamextension.io
+ img: team_extension_north_america_inc.png
+ - name: Free Bets US
+ url: https://freebets.us
+ img: free_bets_us.png
+ - name: Doximity
+ url: https://technology.doximity.com/
+ img: doximity.png
+ - name: Interflora Group
+ url: https://www.interflora.fr
+ img: interflora_group.png
+ - name: Codesmith
+ url: https://codesmith.io
+ img: codesmith.png
+ - name: Optimizers
+ url: https://www.optimizers.nl
+ img: optimizers.png
+ - name: FORTUNE GAMES
+ url: https://www.fortunegames.com
+ img: fortune_games.png
+ - name: Indy
+ url: https://www.indy.fr/
+ img: indy.png
+ - name: Buy Instagram Followers from SocialWick
+ url: https://www.socialwick.com/instagram/followers
+ img: buy_instagram_followers_from_socialwick.png
+ - name: Social Followers
+ url: https://www.socialfollowers.uk/buy-tiktok-followers/
+ img: social_followers.png
+ - name: Nettcasino
+ url: https://www.nettcasino.com/
+ img: nettcasino.png
+ - name: Spelpressen
+ url: https://spelpressen.se/
+ img: spelpressen.png
+ - name: Casino Utan Svensk Licens
+ url: https://casino-utan-svensk-licens.com/
+ img: casino_utan_svensk_licens.png
+ - name: Outlook India
+ url: >-
+ https://www.outlookindia.com/outlook-spotlight/casinos-not-on-gamstop-uk-news-302214/
+ img: outlook_india.png
+bronze:
+ - name: Derek Pollard
+ url: https://polyglotengineer.com/derek.pollard
img: derek_pollard.png
- name: Derek Pollard
- - url: 'https://www.earthlink.ro'
- img: earthlink.png
- name: Earthlink
+ - name: BGASoft
+ url: https://www.bgasoft.com
+ img: bgasoft.png
+ - name: RStudio
+ url: https://rstudio.com
+ img: rstudio.png
+ - name: Darkhorse Analytics
+ url: https://www.darkhorseanalytics.com/
+ img: darkhorse_analytics.png
+ - name: vuejs.de - German Vue Community
+ url: https://vuejs.de
+ img: vuejs_de___german_vue_community.svg
+ - name: Liip AG
+ url: https://www.liip.ch/en
+ img: liip_ag.png
+ - name: Bürkert Werke GmbH & Co KG
+ url: https://www.burkert.com
+ img: b_rkert_werke_gmbh___co_kg.png
+ - name: codefortynine
+ url: https://codefortynine.com
+ img: codefortynine.png
+ - name: Arcanite
+ url: https://arcanite.ch
+ img: arcanite.png
+platinum_china:
+ - name: CRMEB
+ url: http://github.crmeb.net/u/vue
+ img: crmeb.svg?v2
+ description: 开源电商系统
+ - name: MISBoot
+ url: https://vue.misboot.com/#/user/Login?from=vuejs
+ img: misboot.png?v3
+ description: 低代码开发平台
+# END SPONSORS
+redirects:
+ '/v2/api/index.html': '/api/'
+ '/v2/guide/index.html': '/guide/introduction.html'
+ '/v2/guide/installation.html': '/guide/quick-start.html'
+ '/v2/guide/instance.html': '/guide/essentials/application.html' # has page redirects
+ '/v2/guide/syntax.html': '/guide/essentials/template-syntax.html'
+ '/v2/guide/computed.html': '/guide/essentials/computed.html' # has page redirects
+ '/v2/guide/class-and-style.html': '/guide/essentials/class-and-style.html'
+ '/v2/guide/conditional.html': '/guide/essentials/conditional.html'
+ '/v2/guide/list.html': '/guide/essentials/list.html'
+ '/v2/guide/events.html': '/guide/essentials/event-handling.html'
+ '/v2/guide/forms.html': '/guide/essentials/forms.html'
+ '/v2/guide/components.html': '/guide/essentials/component-basics.html'
+ '/v2/guide/components-registration.html': '/guide/components/registration.html'
+ '/v2/guide/components-props.html': '/guide/components/props.html' # has page redirects
+ '/v2/guide/components-custom-events.html': '/guide/components/events.html'
+ '/v2/guide/components-slots.html': '/guide/components/slots.html'
+ '/v2/guide/components-dynamic-async.html': '/guide/built-ins/keep-alive.html' # has page redirects
+ '/v2/guide/transitions.html': '/guide/built-ins/transition.html' # has page redirects
+ '/v2/guide/transitioning-state.html': '/guide/extras/animation.html'
+ '/v2/guide/custom-directive.html': '/guide/reusability/custom-directives.html'
+ '/v2/guide/render-function.html': '/guide/extras/render-function.html'
+ '/v2/guide/plugins.html': '/guide/reusability/plugins.html'
+ '/v2/guide/single-file-components.html': '/guide/scaling-up/sfc.html'
+ '/v2/guide/testing.html': '/guide/scaling-up/testing.html'
+ '/v2/guide/typescript.html': '/guide/typescript/overview.html'
+ '/v2/guide/deployment.html': '/guide/best-practices/production-deployment.html'
+ '/v2/guide/routing.html': '/guide/scaling-up/routing.html'
+ '/v2/guide/state-management.html': '/guide/scaling-up/state-management.html'
+ '/v2/guide/ssr.html': '/guide/scaling-up/ssr.html'
+ '/v2/guide/security.html': '/guide/best-practices/security.html'
+ '/v2/guide/reactivity.html': '/guide/extras/reactivity-in-depth.html'
diff --git a/themes/vue/layout/icons/github-dark.ejs b/themes/vue/layout/icons/github-dark.ejs
index eb71a11da5..296fede1ec 100644
--- a/themes/vue/layout/icons/github-dark.ejs
+++ b/themes/vue/layout/icons/github-dark.ejs
@@ -1 +1 @@
-
GitHub Dark icon
+
GitHub Dark icon
diff --git a/themes/vue/layout/index.ejs b/themes/vue/layout/index.ejs
index 10eed9f2ca..efb5587336 100644
--- a/themes/vue/layout/index.ejs
+++ b/themes/vue/layout/index.ejs
@@ -1,126 +1,157 @@
-