diff --git a/_config.yml b/_config.yml index 1e5654f7e..533800947 100644 --- a/_config.yml +++ b/_config.yml @@ -77,6 +77,11 @@ 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/hexojs/hexo/wiki/Plugins ## Themes: https://github.com/hexojs/hexo/wiki/Themes diff --git a/assets/why-vue/arabic.js.srt b/assets/why-vue/arabic.js.srt index 0388f0dd2..af61b3d07 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 7927ff0a8..6f597d6bd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "cn.vuejs.org", "private": true, "hexo": { - "version": "3.7.1" + "version": "3.8.0" }, "scripts": { "start": "hexo server", diff --git a/src/resources/partners.md b/src/resources/partners.md index 3f0894787..dab1a2b48 100644 --- a/src/resources/partners.md +++ b/src/resources/partners.md @@ -42,7 +42,12 @@ partners_list: name: Modus Create logo: https://res.cloudinary.com/modus-labs/image/upload/v1533109874/modus/logo-vertical-black.svg description: - "Modus Create is a digital product agency that supports clients with business and product strategy consulting, customer experience, cloud services, and Agile software delivery. Our official partnerships with Atlassian, AWS, InVision, Cloudflare, GitHub, Ionic Framework, and Vue.js reinforce our proven results with digital transformation with organizations from startups to the Fortune 100." + "Modus Create is a disruptive consulting firm that helps companies transform for success in the digital future. + + Clients work with Modus to effect transformational change through a unique collaborative engagement model that focuses on strategy, product design/build, user experience, company culture, and process change to accelerate their response to digital disruption. + + Modus is uniquely expert at executing within the new reality of global talent sourcing and globally distributed teams. Modus culture is based on recruiting only top talent regardless of their location. Modus delivers time zone-aligned, highly productive, English-speaking teams, accessibility, and a totally collaborative environment regardless of individual location. +" proficiencies: - name: Vue.js url: https://moduscreate.com/partners/vue/?utm_source=Vue&utm_medium=Partner-Page&utm_campaign=Vue_partnerpage @@ -89,7 +94,7 @@ partners_list: name: Monterail logo: Monterail.png description: - "Monterail is a full-service software development company with 100+ experts on board delivering meaningful software for start-ups, SMBs and enterprises. We build for the Web with Ruby on Rails, Python, JavaScript, and Agile. We guarantee this: a product so qualitative and aligned with your vision, you’ll swear it was built in-house." + "Monterail is a full-service software development company with 110+ experts on board delivering meaningful software for start-ups, SMBs and enterprises. We are organizers of the first official Vue-related conference in the world and authors of the State of Vue.js report (2017&2019). Our experts delivered 30 Vue.js-based projects so far." proficiencies: - name: VueJs url: https://hi.monterail.co/2NqPUa6 @@ -100,15 +105,15 @@ partners_list: - name: Python url: https://hi.monterail.co/2MXHLeb - name: Services - url: https://www.monterail.com/services + url: https://www.monterail.com/services?utm_medium=referral&utm_source=partner-list&utm_campaign=vue.js - name: Projects - url: https://www.monterail.com/projects + url: https://www.monterail.com/projects?utm_medium=referral&utm_source=partner-list&utm_campaign=vue.js location: Wrocław, Poland languages: - English - Polish url_text: www.monterail.com - url_link: www.monterail.com/?utm_campaign=Vue.js&utm_source=partner-list + url_link: www.monterail.com/services/vue-development?utm_campaign=Vue.js&utm_source=partner-list hire_url: www.monterail.com/contact email: hello@monterail.com social_links: diff --git a/src/v2/api/index.md b/src/v2/api/index.md index ad044b4ea..4a1f70407 100644 --- a/src/v2/api/index.md +++ b/src/v2/api/index.md @@ -684,6 +684,7 @@ type: api handler: 'someMethod', immediate: true }, + // 你可以传入回调数组,它们会被逐一调用 e: [ 'handle1', function handle2 (val, oldVal) { /* ... */ }, diff --git a/src/v2/cookbook/debugging-in-vscode.md b/src/v2/cookbook/debugging-in-vscode.md index c9e612fcf..29de5968a 100644 --- a/src/v2/cookbook/debugging-in-vscode.md +++ b/src/v2/cookbook/debugging-in-vscode.md @@ -64,7 +64,7 @@ module.exports = { "webRoot": "${workspaceFolder}/src", "breakOnLoad": true, "sourceMapPathOverrides": { - "webpack:///./src/*": "${webRoot}/*" + "webpack:///src/*": "${webRoot}/*" } }, { diff --git a/src/v2/cookbook/form-validation.md b/src/v2/cookbook/form-validation.md index ea17b37a3..fcfd33095 100644 --- a/src/v2/cookbook/form-validation.md +++ b/src/v2/cookbook/form-validation.md @@ -203,7 +203,7 @@ const app = new Vue({ 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,}))$/; + 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); } } @@ -330,21 +330,26 @@ const app = new Vue({ ## 服务端校验 -在我们最终的示例中,我们构建了一些用到 Ajax 的服务端校验的东西。这个表单将会问你为一个新产品起名字,并且将会确保这个名字是唯一的。我们快速写了一个 [OpenWhisk](http://openwhisk.apache.org/) 的 serverless action 来进行这个校验。虽然这不是非常重要,但其逻辑如下: +在我们最终的示例中,我们构建了一些用到 Ajax 的服务端校验的东西。这个表单将会问你为一个新产品起名字,并且将会确保这个名字是唯一的。我们快速写了一个 [Netlify](https://netlify.com/) 的 serverless action 来进行这个校验。虽然这不是非常重要,但其逻辑如下: ``` js -function main(args) { - return new Promise((resolve, reject) => { - // 不好的产品名:vista, empire, mbp +exports.handler = async (event, context) => { + const badNames = ['vista', 'empire', 'mbp']; - - if (badNames.includes(args.name)) { - reject({error: 'Existing product'}); + const name = event.queryStringParameters.name; + + if (badNames.includes(name)) { + return { + statusCode: 400, + body: JSON.stringify({error: 'Invalid name passed.'}) + } + } + + return { + statusCode: 204 } - - resolve({status: 'ok'}); - }); } + ``` 基本上除了“vista”、“empire”和“mbp”的名字都是可以接受的。好,让我们来看看表单。 @@ -386,7 +391,7 @@ function main(args) { 这里没有任何特殊的东西。接下来我们再看看 JavaScript。 ``` js -const apiUrl = 'https://openwhisk.ng.bluemix.net/api/v1/web/rcamden%40us.ibm.com_My%20Space/safeToDelete/productName.json?name='; +const apiUrl = 'https://vuecookbook.netlify.com/.netlify/functions/product-name?name='; const app = new Vue({ el: '#app', @@ -404,13 +409,12 @@ const app = new Vue({ 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 { - // 在成功的时候重定向到一个新的 URL 或做一些别的事情 - alert('ok!'); + .then(async res => { + if (res.status === 204) { + alert('OK'); + } else if (res.status === 400) { + let errorResponse = await res.json(); + this.errors.push(errorResponse.error); } }); } diff --git a/src/v2/examples/commits.md b/src/v2/examples/commits.md index 065978784..93e12be09 100644 --- a/src/v2/examples/commits.md +++ b/src/v2/examples/commits.md @@ -6,4 +6,4 @@ order: 1 > 这个例子从 Github 的 API 中获取了最新的 Vue.js 提交数据,并且以列表形式将它们展示了出来。你可以轻松地切换 master 和 dev 分支。 - + diff --git a/src/v2/examples/deepstream.md b/src/v2/examples/deepstream.md index 5c927f639..2bbf12f62 100755 --- a/src/v2/examples/deepstream.md +++ b/src/v2/examples/deepstream.md @@ -6,4 +6,4 @@ order: 9 > 这个例子使用 [deepstreamHub](https://deepstreamhub.com/) 在客户端之间实时同步数据、发送事件、远程程序调用 (你可以多开几个浏览器窗口试一试)。 - + diff --git a/src/v2/examples/elastic-header.md b/src/v2/examples/elastic-header.md index 470fd00d5..994bb1947 100644 --- a/src/v2/examples/elastic-header.md +++ b/src/v2/examples/elastic-header.md @@ -4,4 +4,4 @@ type: examples order: 7 --- - + diff --git a/src/v2/examples/firebase.md b/src/v2/examples/firebase.md index 1451d148a..4c347c64c 100644 --- a/src/v2/examples/firebase.md +++ b/src/v2/examples/firebase.md @@ -5,4 +5,5 @@ order: 10 --- > 本示例使用 [Firebase](https://firebase.google.com/) 作为数据存储后端,同时在客户端进行数据实时同步 (你可以在多个浏览器窗口去打开它来验证)。另外,它通过计算属性实时验证,并且添加/移除选项时触发 CSS 过渡。 - + + diff --git a/src/v2/examples/grid-component.md b/src/v2/examples/grid-component.md index 8ed216555..0438e0cf9 100644 --- a/src/v2/examples/grid-component.md +++ b/src/v2/examples/grid-component.md @@ -6,4 +6,4 @@ order: 3 > 本示例创建了一个可复用组件,可结合外部数据来使用它。 - + diff --git a/src/v2/examples/index.md b/src/v2/examples/index.md index b1cc2fa36..f1d1fe2cc 100644 --- a/src/v2/examples/index.md +++ b/src/v2/examples/index.md @@ -6,4 +6,4 @@ order: 0 > 蠢萌的 Markdown 编辑器。 - + diff --git a/src/v2/examples/modal.md b/src/v2/examples/modal.md index 56c93003e..347286d8a 100644 --- a/src/v2/examples/modal.md +++ b/src/v2/examples/modal.md @@ -6,4 +6,4 @@ order: 6 > 使用到的特性:组件,prop 传递,内容插入(content insertion),过渡 (transitions)。 - + diff --git a/src/v2/examples/select2.md b/src/v2/examples/select2.md index 7b34c102d..9fb6e10e5 100644 --- a/src/v2/examples/select2.md +++ b/src/v2/examples/select2.md @@ -6,4 +6,4 @@ order: 8 > 在本例中,我们整合了第三方 jQuery 插件 (select2),怎么做到的呢?就是把它内嵌在一个常用组件中。 - + diff --git a/src/v2/examples/svg.md b/src/v2/examples/svg.md index 67e7c0059..17b087791 100644 --- a/src/v2/examples/svg.md +++ b/src/v2/examples/svg.md @@ -6,4 +6,4 @@ order: 5 > 本示例展示了一个结合体,它由常用组件、计算属性、2 种绑定方式和 SVG 的支持组成。 - + diff --git a/src/v2/examples/todomvc.md b/src/v2/examples/todomvc.md index f87ad587f..4489850bf 100644 --- a/src/v2/examples/todomvc.md +++ b/src/v2/examples/todomvc.md @@ -6,6 +6,6 @@ order: 11 > 本例是一个完全和规范一致的 TodoMVC 实现,只用了 120 行有效的 JavaScript (不包含注释和空行)。 -

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 6426ae918..54d923e80 100644 --- a/src/v2/examples/tree-view.md +++ b/src/v2/examples/tree-view.md @@ -6,4 +6,4 @@ order: 4 > 本示例是一个简单的树形视图实现,它展现了组件的递归使用。 - + 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 000000000..caf5244f4 --- /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 000000000..3dcc5dba3 --- /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 000000000..5866ed744 --- /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 000000000..80ab295e3 --- /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 000000000..40d6041b2 --- /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 000000000..082e912c9 --- /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 000000000..5866ed744 --- /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 000000000..e63f64f86 --- /dev/null +++ b/src/v2/examples/vue-10-two-way-currency-filter/index.html @@ -0,0 +1,56 @@ + + + + Two-way Currency Filter + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +

Total: ${{ total }}

+
+ + + + 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 000000000..ee92d5f0a --- /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 000000000..5866ed744 --- /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 000000000..b446ec77f --- /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 000000000..f01eaa982 --- /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 000000000..5866ed744 --- /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 000000000..4f88009fc --- /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 000000000..65197ee44 --- /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 000000000..5866ed744 --- /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 000000000..47b143b50 --- /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 000000000..a4a7d58da --- /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 000000000..5866ed744 --- /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 000000000..7116c02dc --- /dev/null +++ b/src/v2/examples/vue-20-dynamic-components-with-binding/index.html @@ -0,0 +1,74 @@ + + + + Dynamic Components Example + + + + +
+ + + +
+ + + + 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 000000000..fdff914b6 --- /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 000000000..5866ed744 --- /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 000000000..9098d1bff --- /dev/null +++ b/src/v2/examples/vue-20-dynamic-components/index.html @@ -0,0 +1,68 @@ + + + + Dynamic Components Example + + + + +
+ + + +
+ + + + 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 000000000..67cb7f7c0 --- /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 000000000..5866ed744 --- /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 000000000..ab6ee87c9 --- /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 000000000..6880b4244 --- /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 000000000..5866ed744 --- /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 000000000..26d74a1a5 --- /dev/null +++ b/src/v2/examples/vue-20-elastic-header/index.html @@ -0,0 +1,115 @@ + + + + Elastic Header + + + + + + + +
+ + + + +
+ + + + 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 000000000..636222773 --- /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 000000000..5866ed744 --- /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 000000000..f3fc3f0b5 --- /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 000000000..1335839c1 --- /dev/null +++ b/src/v2/examples/vue-20-firebase-validation/index.html @@ -0,0 +1,96 @@ + + + + Firebase + Validation + + + + + + + +
+ +
+ + + +
+ +
+ + + + 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 000000000..570fb291d --- /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 000000000..5866ed744 --- /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 000000000..761054c0c --- /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 000000000..db344faee --- /dev/null +++ b/src/v2/examples/vue-20-github-commits/index.html @@ -0,0 +1,91 @@ + + + + GitHub Commits + + + + +
+

Latest Vue.js Commits

+ +

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 000000000..8afebc635 --- /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 000000000..5866ed744 --- /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 000000000..c0e705b77 --- /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 000000000..43b96ea54 --- /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 000000000..1734610da --- /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 000000000..5866ed744 --- /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 000000000..f10002ab8 --- /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 000000000..aa8403c6b --- /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 000000000..c02e41273 --- /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 000000000..5866ed744 --- /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 000000000..09ba8c5fc --- /dev/null +++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html @@ -0,0 +1,97 @@ + + + + Vue Component Blog Post Example + + + + +
+ + + + + +
+ + + + 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 000000000..7bf11e28e --- /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 000000000..5866ed744 --- /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 000000000..5681ac6cb --- /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 000000000..538f602c2 --- /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.

+ + + +
+ {{ 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 000000000..f18a53b34 --- /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 000000000..5866ed744 --- /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 000000000..103973e3c --- /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 000000000..0e13a58ee --- /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 000000000..7866640c1 --- /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 000000000..5866ed744 --- /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 000000000..01cacdc9d --- /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 000000000..a6cb24658 --- /dev/null +++ b/src/v2/examples/vue-20-modal-component/index.html @@ -0,0 +1,69 @@ + + + + Modal Component + + + + + + + +
+ + + + +

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 000000000..6d64ba243 --- /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 000000000..5866ed744 --- /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 000000000..d36f166fb --- /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 000000000..dcc0ce7d3 --- /dev/null +++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html @@ -0,0 +1,47 @@ + + + + Priority D Rules Correct Example + + + + +
+ + + + + +

+ 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 000000000..7afc08c22 --- /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 000000000..5866ed744 --- /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 000000000..22ed5bab0 --- /dev/null +++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html @@ -0,0 +1,54 @@ + + + + Priority D Rules Unintended Consequences + + + + +
+ + + + + +

+ 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 000000000..43c1c3a9f --- /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 000000000..5866ed744 --- /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 000000000..48329aba9 --- /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 000000000..42312caa1 --- /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 000000000..5866ed744 --- /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 000000000..639319a9d --- /dev/null +++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html @@ -0,0 +1,184 @@ + + + + Realtime with deepstreamHub + + + + + + + +
+
+ Connection-State is: {{connectionState}} +
+ + + +
+ + + + + + + + + + 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 000000000..abf1458b2 --- /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 000000000..5866ed744 --- /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 000000000..b643051df --- /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 000000000..9ca04cbb4 --- /dev/null +++ b/src/v2/examples/vue-20-single-file-components/Hello.vue @@ -0,0 +1,20 @@ + + + + + \ 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 000000000..865e670f4 --- /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 000000000..4cd7af61f --- /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 000000000..36dd9df6e --- /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 000000000..435a47da5 --- /dev/null +++ b/src/v2/examples/vue-20-svg-graph/index.html @@ -0,0 +1,142 @@ + + + + SVG Graph + + + + + + + + + + + +
+ + + + + +
+ + + {{stat.value}} + +
+
+ + +
+
{{ 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 000000000..afbe362f7 --- /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 000000000..5866ed744 --- /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 000000000..b533e006a --- /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 000000000..b74e68f29 --- /dev/null +++ b/src/v2/examples/vue-20-template-compilation/index.html @@ -0,0 +1,83 @@ + + + + Template Compilation + + + + +
+ +
+ +
{{ result.render }}
+ +
_m({{ index }}): {{ fn }}
+
{{ result.staticRenderFns }}
+
+
+ +
{{ 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 000000000..c802e5660 --- /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 000000000..5866ed744 --- /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 000000000..02a88e450 --- /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 000000000..78337e186 --- /dev/null +++ b/src/v2/examples/vue-20-todomvc/index.html @@ -0,0 +1,258 @@ + + + + TodoMVC + + + + + +
+
+

todos

+ +
+
+ + +
    +
  • +
    + + + +
    + +
  • +
+
+
+ + {{ remaining }} {{ remaining | pluralize }} left + + + +
+
+ + + + + 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 000000000..8fb7dbe6d --- /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 000000000..5866ed744 --- /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 000000000..b5aad8cca --- /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 000000000..911f9e37e --- /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 000000000..5866ed744 --- /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 000000000..39c9133b8 --- /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 000000000..80ab295e3 --- /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 000000000..5ee238cee --- /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 000000000..ef67bd57a --- /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 000000000..5866ed744 --- /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 000000000..fc2b21cc7 --- /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 000000000..92fe02c5c --- /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 000000000..5866ed744 --- /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/comparison.md b/src/v2/guide/comparison.md index d4a087b00..0bbeb25cd 100644 --- a/src/v2/guide/comparison.md +++ b/src/v2/guide/comparison.md @@ -70,7 +70,7 @@ Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。 #### 组件作用域内的 CSS -除非你把组件分布在多个文件上 (例如 [CSS Modules](https://github.com/gajus/react-css-modules)),CSS 作用域在 React 中是通过 CSS-in-JS 的方案实现的 (比如 [styled-components](https://github.com/styled-components/styled-components)、[glamorous](https://github.com/paypal/glamorous) 和 [emotion](https://github.com/emotion-js/emotion))。这引入了一个新的面向组件的样式范例,它和普通的 CSS 撰写过程是有区别的。另外,虽然在构建时将 CSS 提取到一个单独的样式表是支持的,但 bundle 里通常还是需要一个运行时程序来让这些样式生效。当你能够利用 JavaScript 灵活处理样式的同时,也需要权衡 bundle 的尺寸和运行时的开销。 +除非你把组件分布在多个文件上 (例如 [CSS Modules](https://github.com/gajus/react-css-modules)),CSS 作用域在 React 中是通过 CSS-in-JS 的方案实现的 (比如 [styled-components](https://github.com/styled-components/styled-components) 和 [emotion](https://github.com/emotion-js/emotion))。这引入了一个新的面向组件的样式范例,它和普通的 CSS 撰写过程是有区别的。另外,虽然在构建时将 CSS 提取到一个单独的样式表是支持的,但 bundle 里通常还是需要一个运行时程序来让这些样式生效。当你能够利用 JavaScript 灵活处理样式的同时,也需要权衡 bundle 的尺寸和运行时的开销。 如果你是一个 CSS-in-JS 的爱好者,许多主流的 CSS-in-JS 库也都支持 Vue (比如 [styled-components-vue](https://github.com/styled-components/vue-styled-components) 和 [vue-emotion](https://github.com/egoist/vue-emotion))。这里 React 和 Vue 主要的区别是,Vue 设置样式的默认方法是[单文件组件](single-file-components.html)里类似 `style` 的标签。 diff --git a/src/v2/guide/components-dynamic-async.md b/src/v2/guide/components-dynamic-async.md index 929a606e7..ebf10567e 100644 --- a/src/v2/guide/components-dynamic-async.md +++ b/src/v2/guide/components-dynamic-async.md @@ -193,7 +193,7 @@ new Vue({ {% endraw %} -现在这个 *Posts* 标签保持了它的状态 (被选中的文章) 甚至当它未被渲染时也是如此。你可以在[这个 fiddle](https://jsfiddle.net/chrisvfritz/Lp20op9o/) 查阅到完整的代码。 +现在这个 *Posts* 标签保持了它的状态 (被选中的文章) 甚至当它未被渲染时也是如此。你可以在[这个示例](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-keep-alive-with-dynamic-components)查阅到完整的代码。

注意这个 `` 要求被切换到的组件都有自己的名字,不论是通过组件的 `name` 选项还是局部/全局注册。

diff --git a/src/v2/guide/components-edge-cases.md b/src/v2/guide/components-edge-cases.md index 1e84fa56e..4f73448a0 100644 --- a/src/v2/guide/components-edge-cases.md +++ b/src/v2/guide/components-edge-cases.md @@ -63,7 +63,7 @@ this.$root.baz() ``` -这个 `` 组件可以定义一个 `map` 属性,所有的子组件都需要访问它。在这种情况下 `` 可能想要通过类似 `this.$parent.getMap` 的方式访问那个地图,以便为其添加一组标记。你可以在[这里](https://jsfiddle.net/chrisvfritz/ttzutdxh/)查阅这种模式。 +这个 `` 组件可以定义一个 `map` 属性,所有的子组件都需要访问它。在这种情况下 `` 可能想要通过类似 `this.$parent.getMap` 的方式访问那个地图,以便为其添加一组标记。你可以在[这里](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-accessing-parent-component-instance)查阅这种模式。 请留意,尽管如此,通过这种模式构建出来的那个组件的内部仍然是容易出现问题的。比如,设想一下我们添加一个新的 `` 组件,当 `` 在其内部出现的时候,只会渲染那个区域内的标记: @@ -154,7 +154,7 @@ provide: function () { inject: ['getMap'] ``` -你可以在[这里](https://jsfiddle.net/chrisvfritz/tdv8dt3s/)看到完整的示例。相比 `$parent` 来说,这个用法可以让我们在*任意*后代组件中访问 `getMap`,而不需要暴露整个 `` 实例。这允许我们更好的持续研发该组件,而不需要担心我们可能会改变/移除一些子组件依赖的东西。同时这些组件之间的接口是始终明确定义的,就和 `props` 一样。 +你可以在[这里](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dependency-injection)看到完整的示例。相比 `$parent` 来说,这个用法可以让我们在*任意*后代组件中访问 `getMap`,而不需要暴露整个 `` 实例。这允许我们更好的持续研发该组件,而不需要担心我们可能会改变/移除一些子组件依赖的东西。同时这些组件之间的接口是始终明确定义的,就和 `props` 一样。 实际上,你可以把依赖注入看作一部分“大范围有效的 prop”,除了: @@ -233,7 +233,7 @@ methods: { } ``` -查阅[这个 fiddle](https://jsfiddle.net/09jvu65m/) 可以了解到完整的代码。注意,即便如此,如果你发现自己不得不在单个组件里做很多建立和清理的工作,最好的方式通常还是创建更多的模块化组件。在这个例子中,我们推荐创建一个可复用的 `` 组件。 +查阅[这个示例](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-programmatic-event-listeners)可以了解到完整的代码。注意,即便如此,如果你发现自己不得不在单个组件里做很多建立和清理的工作,最好的方式通常还是创建更多的模块化组件。在这个例子中,我们推荐创建一个可复用的 `` 组件。 想了解更多程序化侦听器的内容,请查阅[实例方法 / 事件](https://cn.vuejs.org/v2/api/#实例方法-事件)相关的 API。 diff --git a/src/v2/guide/components.md b/src/v2/guide/components.md index 57cedb35a..0284ad9f7 100644 --- a/src/v2/guide/components.md +++ b/src/v2/guide/components.md @@ -203,7 +203,7 @@ new Vue({ > ``` -如上所示,你会发现我们可以使用 `v-bind` 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如[从一个 API 获取博文列表](https://jsfiddle.net/chrisvfritz/sbLgr0ad)的时候,是非常有用的。 +如上所示,你会发现我们可以使用 `v-bind` 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如[从一个 API 获取博文列表](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-component-blog-post-example)的时候,是非常有用的。 到目前为止,关于 prop 你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把 [prop](components-props.html) 读完。 @@ -601,7 +601,7 @@ new Vue({ - 已注册组件的名字,或 - 一个组件的选项对象 -你可以在[这里](https://jsfiddle.net/chrisvfritz/o3nycadu/)查阅并体验完整的代码,或在[这个版本](https://jsfiddle.net/chrisvfritz/b2qj69o1/)了解绑定组件选项对象,而不是已注册组件名的示例。 +你可以在[这里](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components)查阅并体验完整的代码,或在[这个版本](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components-with-binding)了解绑定组件选项对象,而不是已注册组件名的示例。 请留意,这个 attribute 可以用于常规 HTML 元素,但这些元素将被视为组件,这意味着所有的 attribute **都会作为 DOM attribute 被绑定**。对于像 `value` 这样的 property,若想让其如预期般工作,你需要使用 [`.prop` 修饰器](../api/#v-bind)。 diff --git a/src/v2/guide/events.md b/src/v2/guide/events.md index dd141dcce..3652dd7e0 100644 --- a/src/v2/guide/events.md +++ b/src/v2/guide/events.md @@ -292,10 +292,10 @@ Vue.config.keyCodes.f1 = 112 ```html - + -
Do something
+
Do something
```

请注意修饰键与常规按键不同,在和 `keyup` 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 `ctrl` 的情况下释放其它按键,才能触发 `keyup.ctrl`。而单单释放 `ctrl` 也不会触发事件。如果你想要这样的行为,请为 `ctrl` 换用 `keyCode`:`keyup.17`。

@@ -308,13 +308,13 @@ Vue.config.keyCodes.f1 = 112 ``` html - + - + - + ``` ### 鼠标按钮修饰符 diff --git a/src/v2/guide/forms.md b/src/v2/guide/forms.md index 761b38fbd..eba4b5881 100644 --- a/src/v2/guide/forms.md +++ b/src/v2/guide/forms.md @@ -358,7 +358,7 @@ vm.toggle === 'yes' vm.toggle === 'no' ``` -

这里的 `true-value` 和 `false-value` attribute 并不会影响输入控件的 `value` attribute,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(比如“yes”或“no”),请换用单选按钮。

+

这里的 `true-value` 和 `false-value` attribute 并不会影响输入控件的 `value` attribute,因为浏览器在提交表单时并不会包含未被选中的复选框。如果要确保表单中这两个值中的一个能够被提交,(即“yes”或“no”),请换用单选按钮。

### 单选按钮 @@ -390,11 +390,11 @@ vm.selected.number // => 123 ### `.lazy` -在默认情况下,`v-model` 在每次 `input` 事件触发后将输入框的值与数据进行同步 (除了[上述](#vmodel-ime-tip)输入法组合文字时)。你可以添加 `lazy` 修饰符,从而转变为使用 `change` 事件进行同步: +在默认情况下,`v-model` 在每次 `input` 事件触发后将输入框的值与数据进行同步 (除了[上述](#vmodel-ime-tip)输入法组合文字时)。你可以添加 `lazy` 修饰符,从而转为在 `change` 事件_之后_进行同步: ``` html - + ``` ### `.number` @@ -419,4 +419,6 @@ vm.selected.number // => 123 > 如果你还不熟悉 Vue 的组件,可以暂且跳过这里。 -HTML 原生的输入元素类型并不总能满足需求。幸好,Vue 的组件系统允许你创建具有完全自定义行为且可复用的输入组件。这些输入组件甚至可以和 `v-model` 一起使用!要了解更多,请参阅组件指南中的[自定义输入组件](components-custom-events.html#自定义组件的-v-model)。 +HTML 原生的输入元素类型并不总能满足需求。幸好,Vue 的组件系统允许你创建具有完全自定义行为且可复用的输入组件。这些输入组件甚至可以和 `v-model` 一起使用! + +要了解更多,请参阅组件指南中的[自定义输入组件](components-custom-events.html#自定义组件的-v-model)。 diff --git a/src/v2/guide/index.md b/src/v2/guide/index.md index 1edf7a941..77ce357a5 100644 --- a/src/v2/guide/index.md +++ b/src/v2/guide/index.md @@ -23,7 +23,7 @@ Vue (读音 /vjuː/,类似于 **view**) 是一套用于构建用户界面的** 安装 -尝试 Vue.js 最简单的方法是使用 [JSFiddle 上的 Hello World 例子](https://jsfiddle.net/chrisvfritz/50wL7mdz/)。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue: +尝试 Vue.js 最简单的方法是使用 [Hello World 例子](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-hello-world)。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue: ``` html @@ -76,6 +76,8 @@ var app = new Vue({ 我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是**响应式的**。我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 `app.message` 的值,你将看到上例相应地更新。 +注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 `#app`) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。 + 除了文本插值,我们还可以像这样来绑定元素 attribute: ``` html diff --git a/src/v2/guide/installation.md b/src/v2/guide/installation.md index b113a6260..4a78d40f2 100644 --- a/src/v2/guide/installation.md +++ b/src/v2/guide/installation.md @@ -10,6 +10,10 @@ gz_size: "30.90" Vue **不支持** IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有[兼容 ECMAScript 5 的浏览器](https://caniuse.com/#feat=es5)。 +### 语义化版本控制 + +Vue 在其所有项目中公布的功能和行为都遵循[语义化版本控制](https://semver.org/lang/zh-CN/)。对于未公布的或内部暴露的行为,其变更会描述在[发布说明](https://github.com/vuejs/vue/releases)中。 + ### 更新日志 最新稳定版本:{{vue_version}} diff --git a/src/v2/guide/list.md b/src/v2/guide/list.md index 43d1e83ac..94c18cc3f 100644 --- a/src/v2/guide/list.md +++ b/src/v2/guide/list.md @@ -12,7 +12,7 @@ order: 8 ``` html
    -
  • +
  • {{ item.message }}
@@ -34,7 +34,7 @@ var example1 = new Vue({ {% raw %}
    -
  • +
  • {{item.message}}
@@ -269,103 +269,7 @@ example1.items = example1.items.filter(function (item) { ### 注意事项 -由于 JavaScript 的限制,Vue **不能**检测以下数组的变动: - -1. 当你利用索引直接设置一个数组项时,例如:`vm.items[indexOfItem] = newValue` -2. 当你修改数组的长度时,例如:`vm.items.length = newLength` - -举个例子: - -``` js -var vm = new Vue({ - data: { - items: ['a', 'b', 'c'] - } -}) -vm.items[1] = 'x' // 不是响应性的 -vm.items.length = 2 // 不是响应性的 -``` - -为了解决第一类问题,以下两种方式都可以实现和 `vm.items[indexOfItem] = newValue` 相同的效果,同时也将在响应式系统内触发状态更新: - -``` js -// Vue.set -Vue.set(vm.items, indexOfItem, newValue) -``` -``` js -// Array.prototype.splice -vm.items.splice(indexOfItem, 1, newValue) -``` - -你也可以使用 [`vm.$set`](https://cn.vuejs.org/v2/api/#vm-set) 实例方法,该方法是全局方法 `Vue.set` 的一个别名: - -``` js -vm.$set(vm.items, indexOfItem, newValue) -``` - -为了解决第二类问题,你可以使用 `splice`: - -``` js -vm.items.splice(newLength) -``` - -## 对象变更检测注意事项 - -还是由于 JavaScript 的限制,**Vue 不能检测对象属性的添加或删除**: - -``` js -var vm = new Vue({ - data: { - a: 1 - } -}) -// `vm.a` 现在是响应式的 - -vm.b = 2 -// `vm.b` 不是响应式的 -``` - -对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。但是,可以使用 `Vue.set(object, propertyName, value)` 方法向嵌套对象添加响应式属性。例如,对于: - -``` js -var vm = new Vue({ - data: { - userProfile: { - name: 'Anika' - } - } -}) -``` - -你可以添加一个新的 `age` 属性到嵌套的 `userProfile` 对象: - -``` js -Vue.set(vm.userProfile, 'age', 27) -``` - -你还可以使用 `vm.$set` 实例方法,它只是全局 `Vue.set` 的别名: - -``` js -vm.$set(vm.userProfile, 'age', 27) -``` - -有时你可能需要为已有对象赋值多个新属性,比如使用 `Object.assign()` 或 `_.extend()`。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样: - -``` js -Object.assign(vm.userProfile, { - age: 27, - favoriteColor: 'Vue Green' -}) -``` - -你应该这样做: - -``` js -vm.userProfile = Object.assign({}, vm.userProfile, { - age: 27, - favoriteColor: 'Vue Green' -}) -``` +由于 JavaScript 的限制,Vue **不能检测**数组和对象的变化。[深入响应式原理](reactivity.html#检测变化的注意事项)中有相关的讨论。 ## 显示过滤/排序后的结果 @@ -392,13 +296,15 @@ computed: { 在计算属性不适用的情况下 (例如,在嵌套 `v-for` 循环中) 你可以使用一个方法: -``` html -
  • {{ n }}
  • +```html +
      +
    • {{ n }}
    • +
    ``` -``` js +```js data: { - numbers: [ 1, 2, 3, 4, 5 ] + sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]] }, methods: { even: function (numbers) { diff --git a/src/v2/guide/migration.md b/src/v2/guide/migration.md index bbe3b794c..a5ac618a9 100644 --- a/src/v2/guide/migration.md +++ b/src/v2/guide/migration.md @@ -1088,17 +1088,17 @@ function pluralizeKnife (count) { 我们现在做一次双向汇率过滤器的迁移作为示范: - + -它基本工作良好,但是拖延的状态更新会导致奇怪的行为。比如,点击 `Result` 标签,试着在其中一个输入框中输入 `9.999`。当输入框失去焦点的时候,其值将会更新到 `$10.00`。然而当我们从整个计算器的角度看时,你会发现存储的数据是 `9.999`。用户看到的已经不是真实的同步了! +它基本工作良好,但是拖延的状态更新会导致奇怪的行为。比如试着在其中一个输入框中输入 `9.999`。当输入框失去焦点的时候,其值将会更新到 `$10.00`。然而当我们从整个计算器的角度看时,你会发现存储的数据是 `9.999`。用户看到的已经不是真实的同步了! 为了过渡到一个更加健壮的 Vue 2.0 的方案,让我们首先在一个新的 `` 组件中包裹这个过滤器: - + 它允许我们添加独立过滤器无法封装的行为,比如选择输入框聚焦的内容。下一步我们从过滤器中提取业务逻辑。接下来是我们把所有的东西放到一个外部的 [`currencyValidator` 对象](https://gist.github.com/chrisvfritz/5f0a639590d6e648933416f90ba7ae4e)中: - + 这会更加模块化,不只是更容易的迁移到 Vue 2,同时也允许汇率间隙和格式化: @@ -1109,7 +1109,7 @@ function pluralizeKnife (count) { 然而在 Vue 1.0 的过滤器中,我们仍然是受限的,所以还是完全升级到 Vue 2.0 吧: - + 你可能注意到了: diff --git a/src/v2/guide/reactivity.md b/src/v2/guide/reactivity.md index aed750099..5a3a5bf5c 100644 --- a/src/v2/guide/reactivity.md +++ b/src/v2/guide/reactivity.md @@ -20,7 +20,11 @@ order: 601 ## 检测变化的注意事项 -受现代 JavaScript 的限制 (而且 `Object.observe` 也已经被废弃),Vue **无法检测到对象属性的添加或删除**。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 `data` 对象上存在才能让 Vue 将它转换为响应式的。例如: +由于 JavaScript 的限制,Vue **不能检测**数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 + +### 对于对象 + +Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化,所以属性必须在 `data` 对象上存在才能让 Vue 将它转换为响应式的。例如: ``` js var vm = new Vue({ @@ -54,7 +58,47 @@ this.$set(this.someObject,'b',2) this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) ``` -也有一些数组相关的注意事项,之前已经在[列表渲染](list.html#注意事项)中讲过。 +### 对于数组 + +Vue 不能检测以下数组的变动: + +1. 当你利用索引直接设置一个数组项时,例如:`vm.items[indexOfItem] = newValue` +2. 当你修改数组的长度时,例如:`vm.items.length = newLength` + +举个例子: + +``` js +var vm = new Vue({ + data: { + items: ['a', 'b', 'c'] + } +}) +vm.items[1] = 'x' // 不是响应性的 +vm.items.length = 2 // 不是响应性的 +``` + +为了解决第一类问题,以下两种方式都可以实现和 `vm.items[indexOfItem] = newValue` 相同的效果,同时也将在响应式系统内触发状态更新: + +``` js +// Vue.set +Vue.set(vm.items, indexOfItem, newValue) +``` +``` js +// Array.prototype.splice +vm.items.splice(indexOfItem, 1, newValue) +``` + +你也可以使用 [`vm.$set`](https://cn.vuejs.org/v2/api/#vm-set) 实例方法,该方法是全局方法 `Vue.set` 的一个别名: + +``` js +vm.$set(vm.items, indexOfItem, newValue) +``` + +为了解决第二类问题,你可以使用 `splice`: + +``` js +vm.items.splice(newLength) +``` ## 声明响应式属性 diff --git a/src/v2/guide/render-function.md b/src/v2/guide/render-function.md index 84d6fd663..3b22cb116 100644 --- a/src/v2/guide/render-function.md +++ b/src/v2/guide/render-function.md @@ -435,6 +435,7 @@ render: function (createElement) { ``` js render: function (createElement) { + // `
    {{ props.text }}
    ` return createElement('div', [ createElement('child', { // 在数据对象中传递 `scopedSlots` @@ -633,6 +634,4 @@ Vue.component('my-functional-button', { 你可能会有兴趣知道,Vue 的模板实际上被编译成了渲染函数。这是一个实现细节,通常不需要关心。但如果你想看看模板的功能具体是怎样被编译的,可能会发现会非常有意思。下面是一个使用 `Vue.compile` 来实时编译模板字符串的简单示例: -{% raw %} - -{% endraw %} + diff --git a/src/v2/guide/security.md b/src/v2/guide/security.md index 95fadec75..f10a846a4 100644 --- a/src/v2/guide/security.md +++ b/src/v2/guide/security.md @@ -6,10 +6,23 @@ order: 504 ## 报告安全漏洞 -当我们收到一个安全漏洞报告,将给予其最高优先级,并由全职贡献者停下手中的工作处理此事。如发现任何安全漏洞,请邮件给 [vuejs.org@gmail.com](mailto:vuejs.org@gmail.com)。 +当我们收到一个安全漏洞报告,将给予其最高优先级,并由全职贡献者停下手中的工作处理此事。如发现任何安全漏洞,请邮件给 [security@vuejs.org](mailto:security@vuejs.org)。 虽然发现新安全漏洞是比较罕见的事,我们仍推荐始终使用最新版本的 Vue 及其官方的周边库,以确保应用尽可能安全。 +## 第一原则:永远不要使用不可信任的模板 + +在使用 Vue 的时候最基本的安全规则是**永远不要将不可信任的内容作为模板内容使用**。这样做等价于允许在应用程序中执行任意的 JavaScript——甚至更糟的是如果在服务端渲染的话可能导致服务器被攻破。举个例子: + +``` js +new Vue({ + el: '#app', + template: `
    ` + userProvidedString + `
    ` // 永远不要这样做 +}) +``` + +Vue 的模板是被编译为 JavaScript 的,而其中的表达式会作为渲染流程的一部分执行。尽管该表达式是在一个特定的渲染上下文中进行运算的。考虑到潜在的全局运行环境的复杂性,作为类似 Vue 的框架,想要完全让代码远离潜在的恶意代码执行而不导致性能问题,是不切实际的。最直接的回避这类问题的方式就是确保 Vue 模板的内容始终是可信的且完全由你掌控。 + ## Vue 的安全措施 ### HTML 内容 @@ -118,7 +131,7 @@ order: 504 让我们假设 `sanitizedUrl` 已经被过滤过了,所以这已经是一个完全真实的 URL 且没有 JavaScript。但通过 `userProvidedStyles`,恶意用户仍可以提供 CSS 来进行“点击诈骗”,例如将链接的样式设置为一个透明的方框覆盖在“登录”按钮之上。然后再把 `https://user-controlled-website.com/` 做成你的应用的登录页的样子,它们就可能获取一个用户真实的登录信息。 -你可以想象到,允许用户为一个 ` @@ -159,7 +172,7 @@ order: 504 除了上述关于[潜在危险](#潜在危险)的建议,我们也推荐自行熟悉以下资料: - [HTML5 Security Cheat Sheet](https://html5sec.org/) -- [OWASP's Cross Site Scripting (XSS) Prevention Cheat Sheet](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet) +- [OWASP's Cross Site Scripting (XSS) Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) 然后利用学到的知识,对那些包含了第三方组件或通过其它方式影响渲染到 DOM 的内容的依赖的源代码进行重新审查,以发现潜在的危险模式。 diff --git a/src/v2/guide/single-file-components.md b/src/v2/guide/single-file-components.md index 85fa05c7f..290e01c09 100644 --- a/src/v2/guide/single-file-components.md +++ b/src/v2/guide/single-file-components.md @@ -21,7 +21,7 @@ order: 401 这是一个文件名为 `Hello.vue` 的简单实例: -单文件组件的示例 (点击查看文本版的代码) +单文件组件的示例 (点击查看文本版的代码 现在我们获得: diff --git a/src/v2/guide/state-management.md b/src/v2/guide/state-management.md index 337f795c8..fca27bdba 100644 --- a/src/v2/guide/state-management.md +++ b/src/v2/guide/state-management.md @@ -19,13 +19,13 @@ order: 502 经常被忽略的是,Vue 应用中原始 `data` 对象的实际来源——当访问数据对象时,一个 Vue 实例只是简单的代理访问。所以,如果你有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享: ``` js -const sourceOfTruth = {} +var sourceOfTruth = {} -const vmA = new Vue({ +var vmA = new Vue({ data: sourceOfTruth }) -const vmB = new Vue({ +var vmB = new Vue({ data: sourceOfTruth }) ``` diff --git a/src/v2/guide/team.md b/src/v2/guide/team.md index 16d87a285..c7a08ed4c 100644 --- a/src/v2/guide/team.md +++ b/src/v2/guide/team.md @@ -308,26 +308,6 @@ order: 803 }] team = team.concat(shuffle([ - { - name: 'Chris Fritz', - title: 'Good Word Putter-Togetherer', - city: 'Lansing, MI, USA', - languages: ['en', 'de'], - github: 'chrisvfritz', - twitter: 'chrisvfritz', - work: { - role: 'Educator & Consultant' - }, - reposOfficial: [ - 'vuejs.org', 'vue-migration-helper' - ], - reposPersonal: [ - 'vue-2.0-simple-routing-example', 'vue-ssr-demo-simple' - ], - links: [ - 'https://www.patreon.com/chrisvuefritz' - ] - }, { name: 'Eduardo', title: 'Real-Time Rerouter', @@ -493,26 +473,6 @@ order: 803 'http://patreon.com/akryum' ] }, - { - name: 'Edd Yerburgh', - title: 'Testatron Alpha 9000', - city: 'London, UK', - languages: ['en'], - github: 'eddyerburgh', - twitter: 'EddYerburgh', - work: { - role: 'Full Stack Developer' - }, - reposOfficial: [ - 'vue-test-utils' - ], - reposPersonal: [ - 'avoriaz' - ], - links: [ - 'https://www.eddyerburgh.me' - ] - }, { name: 'Sarah Drasner', city: 'Denver, CO, USA', @@ -668,9 +628,62 @@ order: 803 'eslint-plugin-vue' ], }, + { + name: 'Ben Hong', + title: 'Proud Ravenclaw Dragon', + city: 'Washington, DC, USA', + languages: ['en', 'zh'], + work: { + role: 'Senior Frontend Engineer', + org: 'GitLab (Meltano)', + }, + reposOfficial: [ + 'vuejs.org', + 'vuepress', + 'vuejs/events' + ], + github: 'bencodezen', + twitter: 'bencodezen', + links: [ + 'https://bencodezen.io/' + ] + }, + { + name: 'Kia King Ishii', + title: 'The optimist web designer/developer', + city: 'Kanagawa, Japan', + languages: ['en', 'jp'], + work: { + role: 'Tech Talent', + org: 'Global Brain', + orgUrl: 'https://globalbrains.com/' + }, + github: 'kiaking', + twitter: 'KiaKing85', + reposOfficial: [ + 'vuex' + ], + reposPersonal: [ + 'vuex-orm/*' + ] + } ])) var emeriti = shuffle([ + { + name: 'Chris Fritz', + title: 'Good Word Putter-Togetherer', + city: 'Durham, NC, USA', + languages: ['en', 'de'], + github: 'chrisvfritz', + twitter: 'chrisvfritz', + work: { + role: 'Educator & Consultant' + }, + reposPersonal: [ + 'vue-enterprise-boilerplate' + ] + }, { name: 'Blake Newman', title: 'Performance Specializer & Code Deleter', @@ -749,6 +762,26 @@ order: 803 orgUrl: 'http://neolant.ru/' } }, + { + name: 'Edd Yerburgh', + title: 'Testatron Alpha 9000', + city: 'London, UK', + languages: ['en'], + github: 'eddyerburgh', + twitter: 'EddYerburgh', + work: { + role: 'Full Stack Developer' + }, + reposOfficial: [ + 'vue-test-utils' + ], + reposPersonal: [ + 'avoriaz' + ], + links: [ + 'https://www.eddyerburgh.me' + ] + } ]) var partners = [ @@ -810,21 +843,6 @@ order: 803 'https://vuejs.amsterdam' ] }, - { - name: 'James McGlasson', - title: 'Head of Marketing Communications', - city: 'Amsterdam, Netherlands', - languages: ['en', 'nl', 'de'], - work: { - role: 'Head Of Marketing Communications', - org: 'Vue.js Amsterdam' - }, - twitter: 'jamesvuejs', - linkedin: 'jdog', - links: [ - 'https://vuejs.amsterdam' - ] - }, { name: 'Jen Looper', title: 'Queen Fox', @@ -1096,24 +1114,6 @@ order: 803 'https://vuejsdevelopers.com' ] }, - { - name: 'Ben Hong', - title: '', - city: 'Washington, DC, USA', - languages: ['en', 'zh'], - work: { - role: 'Senior Frontend Engineer', - org: 'GitLab (Meltano)', - }, - reposOfficial: [ - 'vuejs/events' - ], - github: 'bencodezen', - twitter: 'bencodezen', - links: [ - 'https://bencodezen.io/' - ] - }, { name: 'EGOIST', title: 'Build Tool Simplificator', diff --git a/src/v2/guide/transitioning-state.md b/src/v2/guide/transitioning-state.md index ddaaf0be8..833752eff 100644 --- a/src/v2/guide/transitioning-state.md +++ b/src/v2/guide/transitioning-state.md @@ -18,7 +18,7 @@ Vue 的过渡系统提供了非常多简单的方法设置进入、离开和列 通过侦听器我们能监听到任何数值属性的数值更新。可能听起来很抽象,所以让我们先来看看使用 [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 %} -上述 demo 背后的代码可以通过[这个 fiddle](https://jsfiddle.net/chrisvfritz/65gLu2b6/) 进行详阅。 +上述 demo 背后的代码可以通过[这个示例](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-state-transitions)进行详阅。 ## 把过渡放到组件里 diff --git a/src/v2/guide/transitions.md b/src/v2/guide/transitions.md index 799d5764a..83521c9e0 100644 --- a/src/v2/guide/transitions.md +++ b/src/v2/guide/transitions.md @@ -1247,7 +1247,7 @@ new Vue({

    需要注意的是使用 FLIP 过渡的元素不能设置为 `display: inline` 。作为替代方案,可以设置为 `display: inline-block` 或者放置于 flex 中

    -FLIP 动画不仅可以实现单列过渡,多维网格也[同样可以过渡](https://jsfiddle.net/chrisvfritz/sLrhk1bc/): +FLIP 动画不仅可以实现单列过渡,多维网格也[同样可以过渡](https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-list-move-transitions): {% raw %}
    diff --git a/src/v2/guide/unit-testing.md b/src/v2/guide/unit-testing.md index ca1f91857..63a42221c 100644 --- a/src/v2/guide/unit-testing.md +++ b/src/v2/guide/unit-testing.md @@ -29,15 +29,17 @@ order: 402 ``` -然后随着 Vue 导入组件的选项,你可以使用许多常见的断言 (这里我们使用的是 Jasmine/Jest 风格的 `expect` 断言作为示例): +然后随着 [Vue Test Utils](https://vue-test-utils.vuejs.org/) 导入组件,你可以使用许多常见的断言 (这里我们使用的是 Jest 风格的 `expect` 断言作为示例): ``` js -// 导入 Vue.js 和组件,进行测试 -import Vue from 'vue' -import MyComponent from 'path/to/MyComponent.vue' +// 导入 Vue Test Utils 内的 `shallowMount` 和待测试的组件 +import { shallowMount } from '@vue/test-utils' +import MyComponent from './MyComponent.vue' -// 这里是一些 Jasmine 2.0 的测试,你也可以使用你喜欢的任何断言库或测试工具。 +// 挂载这个组件 +const wrapper = shallowMount(MyComponent) +// 这里是一些 Jest 的测试,你也可以使用你喜欢的任何断言库或测试 describe('MyComponent', () => { // 检查原始组件选项 it('has a created hook', () => { @@ -53,15 +55,12 @@ describe('MyComponent', () => { // 检查 mount 中的组件实例 it('correctly sets the message when created', () => { - const vm = new Vue(MyComponent).$mount() - expect(vm.message).toBe('bye!') + expect(wrapper.vm.$data.message).toBe('bye!') }) // 创建一个实例并检查渲染输出 it('renders the correct message', () => { - const Constructor = Vue.extend(MyComponent) - const vm = new Constructor().$mount() - expect(vm.$el.textContent).toBe('bye!') + expect(wrapper.text()).toBe('bye!') }) }) ``` @@ -82,47 +81,49 @@ describe('MyComponent', () => { ``` -你可以在不同的 props 中,通过 `propsData` 选项断言它的渲染输出: +你可以使用 [Vue Test Utils](https://vue-test-utils.vuejs.org/) 来在输入不同 prop 时为渲染输出下断言: ``` js -import Vue from 'vue' +import { shallowMount } from '@vue/test-utils' import MyComponent from './MyComponent.vue' -// 挂载元素并返回已渲染的文本的工具函数 -function getRenderedText (Component, propsData) { - const Constructor = Vue.extend(Component) - const vm = new Constructor({ propsData: propsData }).$mount() - return vm.$el.textContent +// 挂载元素并返回已渲染的组件的工具函数 +function getMountedComponent(Component, propsData) { + return shallowMount(Component, { + propsData + }) } describe('MyComponent', () => { it('renders correctly with different props', () => { - expect(getRenderedText(MyComponent, { - msg: 'Hello' - })).toBe('Hello') - - expect(getRenderedText(MyComponent, { - msg: 'Bye' - })).toBe('Bye') + expect( + getMountedComponent(MyComponent, { + msg: 'Hello' + }).text() + ).toBe('Hello') + + expect( + getMountedComponent(MyComponent, { + msg: 'Bye' + }).text() + ).toBe('Bye') }) }) ``` ## 断言异步更新 -由于 Vue 进行 [异步更新 DOM](reactivity.html#异步更新队列) 的情况,一些依赖 DOM 更新结果的断言必须在 `Vue.nextTick` 回调中进行: +由于 Vue 进行 [异步更新 DOM](reactivity.html#异步更新队列) 的情况,一些依赖 DOM 更新结果的断言必须在 `vm.$nextTick()` resolve 之后进行: ``` js // 在状态更新后检查生成的 HTML -it('updates the rendered message when vm.message updates', done => { - const vm = new Vue(MyComponent).$mount() - vm.message = 'foo' +it('updates the rendered message when wrapper.message updates', async () => { + const wrapper = shallowMount(MyComponent) + wrapper.setData({ message: 'foo' }) // 在状态改变后和断言 DOM 更新前等待一刻 - Vue.nextTick(() => { - expect(vm.$el.textContent).toBe('foo') - done() - }) + await wrapper.vm.$nextTick() + expect(wrapper.text()).toBe('foo') }) ``` diff --git a/src/v2/style-guide/index.md b/src/v2/style-guide/index.md index d759013b8..0ad77f949 100644 --- a/src/v2/style-guide/index.md +++ b/src/v2/style-guide/index.md @@ -792,7 +792,7 @@ components/ - 因为这些组件会被频繁使用,所以你可能想把它们放到全局而不是在各处分别导入它们。使用相同的前缀可以让 webpack 这样工作: ``` js - var requireComponent = require.context("./src", true, /^Base[A-Z]/) + var requireComponent = require.context("./src", true, /Base[A-Z]\w+\.(vue|js)$/) requireComponent.keys().forEach(function (fileName) { var baseComponentConfig = requireComponent(fileName) baseComponentConfig = baseComponentConfig.default || baseComponentConfig @@ -1501,7 +1501,7 @@ computed: { ``` html