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 735830446a..2e073bbcb6 100644
--- a/src/v2/api/index.md
+++ b/src/v2/api/index.md
@@ -246,11 +246,11 @@ type: api
- **See also:** [Async Update Queue](../guide/reactivity.html#Async-Update-Queue)
-### Vue.set( target, key, value )
+### Vue.set( target, propertyName/index, value )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- `{any} value`
- **Returns:** the set value.
@@ -263,11 +263,11 @@ type: api
- **See also:** [Reactivity in Depth](../guide/reactivity.html)
-### Vue.delete( target, key )
+### Vue.delete( target, propertyName/index )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key/index`
+ - `{string | number} propertyName/index`
> Only in 2.2.0+: Also works with Array + index.
@@ -674,16 +674,17 @@ type: api
},
// string method name
b: 'someMethod',
- // deep watcher
+ // the callback will be called whenever any of the watched object properties change regardless of their nested depth
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
// the callback will be called immediately after the start of the observation
d: {
- handler: function (val, oldVal) { /* ... */ },
+ 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,11 +1579,40 @@ type: api
// `callback` is fired immediately with current value of `a`
```
-### vm.$set( target, key, value )
+ 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:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- `{any} value`
- **Returns:** the set value.
@@ -1591,11 +1623,11 @@ type: api
- **See also:** [Vue.set](#Vue-set)
-### vm.$delete( target, key )
+### vm.$delete( target, propertyName/index )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- **Usage:**
@@ -2013,7 +2045,7 @@ type: api
``` html
-
+
```
The default behavior of `v-for` will try to patch the elements in-place without moving them. To force it to reorder elements, you need to provide an ordering hint with the `key` special attribute:
@@ -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/index.md b/src/v2/cookbook/index.md
index 1a0f0c24a9..54b401ed02 100644
--- a/src/v2/cookbook/index.md
+++ b/src/v2/cookbook/index.md
@@ -16,6 +16,8 @@ How is the cookbook different from the guide? Why is this necessary?
* **Exploring the Ecosystem**: For advanced features, we assume some ecosystem knowledge. For example, if you want to use single-file components in Webpack, we don't explain how to configure the non-Vue parts of the Webpack config. In the cookbook, we have the space to explore these ecosystem libraries in more depth - at least to the extent that is universally useful for Vue developers.
+With all these differences, please note that the cookbook is still _not_ a step-by-step manual. For most of its content, you are expected to have a basic understanding of concepts like HTML, CSS, JavaScript, npm/yarn, etc.
+
## Cookbook Contributions
### What we're looking for
diff --git a/src/v2/cookbook/packaging-sfc-for-npm.md b/src/v2/cookbook/packaging-sfc-for-npm.md
index fe1e37ea50..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 9d59c38113..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).
@@ -86,7 +86,7 @@ If you are a fan of CSS-in-JS, many of the popular CSS-in-JS libraries support V
The optional `scoped` attribute automatically scopes this CSS to your component by adding a unique attribute (such as `data-v-21e5b78`) to elements and compiling `.list-container:hover` to something like `.list-container[data-v-21e5b78]:hover`.
-Lastly, the styling in Vue's single-file component's is very flexible. Through [vue-loader](https://github.com/vuejs/vue-loader), you can use any preprocessor, post-processor, and even deep integration with [CSS Modules](https://vue-loader.vuejs.org/en/features/css-modules.html) -- all within the `
+```
+
+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 e180ed6934..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 })
@@ -581,6 +588,8 @@ and custom JavaScript hooks:
```
+In the example above, either `appear` attribute or `v-on:appear` hook will cause an appear transition.
+
## Transitioning Between Elements
We discuss [transitioning between components](#Transitioning-Between-Components) later, but you can also transition between raw elements using `v-if`/`v-else`. One of the most common two-element transitions is between a list container and a message describing an empty list:
@@ -957,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
@@ -1241,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 26f5fabb48..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. In our next major version of Vue (3.x), we are also planning to considerably improve our TypeScript support with built-in class based components API and TSX 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 85baef28cd..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__
@@ -1433,7 +1417,7 @@ While attribute values without any spaces are not required to have quotes in HTM
### Directive shorthands
strongly recommended
-**Directive shorthands (`:` for `v-bind:` and `@` for `v-on:`) should be used always or never.**
+**Directive shorthands (`:` for `v-bind:`, `@` for `v-on:` and `#` for `v-slot`) should be used always or never.**
{% raw %}
{% endraw %}
#### Bad
@@ -1451,6 +1435,16 @@ While attribute values without any spaces are not required to have quotes in HTM
@focus="onFocus"
>
```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
{% raw %}
{% endraw %}
{% raw %}
{% endraw %}
@@ -1483,6 +1477,26 @@ While attribute values without any spaces are not required to have quotes in HTM
v-on:focus="onFocus"
>
```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
{% raw %}
{% endraw %}
@@ -1582,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`
@@ -1726,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
@@ -1777,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 %}
@@ -1912,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 8cfdf1a106..ae2c91815a 100644
--- a/themes/vue/_config.yml
+++ b/themes/vue/_config.yml
@@ -1,126 +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://moduscreate.com/?utm_source=Vue&utm_medium=Partnership&utm_campaign=VueShip
- img: modus.png
- name: Modus
- - url: >-
- https://www.bitsrc.io/?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://vuetifyjs.com'
- img: vuetify.png
- name: Vuetify
- - 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: 'https://www.bestvpn.co/'
- img: bestvpn_co.png
- name: BestVPN.co
- - 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
-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: Y8
+ url: https://www.y8.com/
+ img: y8.png
+ - name: DevExpress
+ url: https://js.devexpress.com/
+ img: devexpress.png
+ - 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 @@
-