style: format html&markdown files (#11531)

This commit is contained in:
Kevin Deng 三咲智子 2024-08-07 10:57:18 +08:00 committed by GitHub
parent 7c75cc3988
commit 8a99f903db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 1445 additions and 1313 deletions

View File

@ -74,9 +74,9 @@ The scope could be anything specifying the place of the commit change. For examp
The subject contains a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* no dot (.) at the end
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### Body

View File

@ -35,7 +35,6 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before
Another aspect of it is that large scale stylistic changes result in massive diffs that touch multiple files, adding noise to the git history and makes tracing behavior changes across commits more cumbersome.
### Pull Request Checklist
- Vue core has two primary work branches: `main` and `minor`.

View File

@ -80,6 +80,7 @@ Depending on the type of the PR, different considerations need to be taken into
- Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in @vue/shared are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`.
- Performance
- Be careful about code changes in "hot paths", in particular the Virtual DOM renderer (`runtime-core/src/renderer.ts`) and component instantiation code.
- Potential Breakage

View File

@ -1,4 +1,3 @@
dist
*.md
*.html
pnpm-lock.yaml
CHANGELOG*.md

View File

@ -10,6 +10,6 @@ Please note that we do not consider XSS via template expressions a valid attack
We would like to thank the following security researchers for responsibly disclosing security issues to us.
- Jeet Pal - [@jeetpal2007](https://github.com/jeetpal2007) | [Email](jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290 )
- Jeet Pal - [@jeetpal2007](https://github.com/jeetpal2007) | [Email](jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290)
- Mix - [@mnixry](https://github.com/mnixry)
- Aviv Keller - [@RedYetiDev](https://github.com/redyetidev) | [LinkedIn](https://www.linkedin.com/in/redyetidev) <redyetidev@gmail.com>

View File

@ -13,7 +13,7 @@ const { render, createApp } = createRenderer({
patchProp,
insert,
remove,
createElement
createElement,
// ...
})

View File

@ -1,12 +1,12 @@
# @vue/runtime-dom
``` js
```js
import { h, createApp } from '@vue/runtime-dom'
const RootComponent = {
render() {
return h('div', 'hello world')
}
},
}
createApp(RootComponent).mount('#app')

View File

@ -4,7 +4,7 @@ This is for Vue's own internal tests only - it ensures logic tested using this p
It can also be used as a reference for implementing a custom renderer.
``` js
```js
import { h, render, nodeOps, dumpOps } from '@vue/runtime-test'
const App = {

View File

@ -11,7 +11,7 @@
```ts
function renderToString(
input: App | VNode,
context?: SSRContext
context?: SSRContext,
): Promise<string>
```
@ -23,7 +23,7 @@ const { renderToString } = require('@vue/server-renderer')
const app = createSSRApp({
data: () => ({ msg: 'hello' }),
template: `<div>{{ msg }}</div>`
template: `<div>{{ msg }}</div>`,
})
;(async () => {
@ -74,7 +74,7 @@ Render and pipe to an existing [Node.js Writable stream](https://nodejs.org/api/
function pipeToNodeWritable(
input: App | VNode,
context: SSRContext = {},
writable: Writable
writable: Writable,
): void
```
@ -94,7 +94,7 @@ Renders input as a [Web ReadableStream](https://developer.mozilla.org/en-US/docs
```ts
function renderToWebStream(
input: App | VNode,
context?: SSRContext
context?: SSRContext,
): ReadableStream
```
@ -117,7 +117,7 @@ Render and pipe to an existing [Web WritableStream](https://developer.mozilla.or
function pipeToWebWritable(
input: App | VNode,
context: SSRContext = {},
writable: WritableStream
writable: WritableStream,
): void
```
@ -144,7 +144,7 @@ Renders input in streaming mode using a simple readable interface.
function renderToSimpleStream(
input: App | VNode,
context: SSRContext,
options: SimpleReadable
options: SimpleReadable,
): SimpleReadable
interface SimpleReadable {
@ -172,7 +172,7 @@ renderToSimpleStream(
},
destroy(err) {
// error encountered
}
}
},
},
)
```

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@ -7,10 +7,13 @@
<link rel="icon" type="image/svg" href="/logo.svg" />
<title>Vue SFC Playground</title>
<script>
const savedPreferDark = localStorage.getItem('vue-sfc-playground-prefer-dark')
const savedPreferDark = localStorage.getItem(
'vue-sfc-playground-prefer-dark',
)
if (
savedPreferDark === 'true' ||
(!savedPreferDark && window.matchMedia('(prefers-color-scheme: dark)').matches)
(!savedPreferDark &&
window.matchMedia('(prefers-color-scheme: dark)').matches)
) {
document.documentElement.classList.add('dark')
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

View File

@ -1,6 +1,10 @@
<title>Vue Template Explorer</title>
<link rel="stylesheet" data-name="vs/editor/editor.main" href="https://unpkg.com/monaco-editor@0.20.0/min/vs/editor/editor.main.css">
<link rel="stylesheet" href="./style.css">
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="https://unpkg.com/monaco-editor@0.20.0/min/vs/editor/editor.main.css"
/>
<link rel="stylesheet" href="./style.css" />
<div id="header"></div>
<div id="source" class="editor"></div>
@ -8,13 +12,13 @@
<script src="https://unpkg.com/monaco-editor@0.20.0/min/vs/loader.js"></script>
<script>
require.config({
require.config({
paths: {
'vs': 'https://unpkg.com/monaco-editor@0.20.0/min/vs'
}
})
vs: 'https://unpkg.com/monaco-editor@0.20.0/min/vs',
},
})
</script>
<script src="./dist/template-explorer.global.js"></script>
<script>
require(['vs/editor/editor.main'], init /* injected by build */)
require(['vs/editor/editor.main'], init /* injected by build */)
</script>

View File

@ -1,6 +1,10 @@
<title>Vue Template Explorer</title>
<link rel="stylesheet" data-name="vs/editor/editor.main" href="./node_modules/monaco-editor/min/vs/editor/editor.main.css">
<link rel="stylesheet" href="./style.css">
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="./node_modules/monaco-editor/min/vs/editor/editor.main.css"
/>
<link rel="stylesheet" href="./style.css" />
<div id="header"></div>
<div id="source" class="editor"></div>
@ -8,13 +12,13 @@
<script src="./node_modules/monaco-editor/min/vs/loader.js"></script>
<script>
require.config({
require.config({
paths: {
'vs': './node_modules/monaco-editor/min/vs'
}
})
vs: './node_modules/monaco-editor/min/vs',
},
})
</script>
<script src="./dist/template-explorer.global.js"></script>
<script>
require(['vs/editor/editor.main'], init /* injected by build */)
require(['vs/editor/editor.main'], init /* injected by build */)
</script>

View File

@ -84,12 +84,12 @@ The following workflow walks through the steps of migrating an actual Vue 2 app
...options,
compilerOptions: {
compatConfig: {
MODE: 2
}
}
MODE: 2,
},
},
}
})
}
},
}
```
@ -103,8 +103,8 @@ The following workflow walks through the steps of migrating an actual Vue 2 app
module.exports = {
resolve: {
alias: {
vue: '@vue/compat'
}
vue: '@vue/compat',
},
},
module: {
rules: [
@ -114,13 +114,13 @@ The following workflow walks through the steps of migrating an actual Vue 2 app
options: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
}
]
}
MODE: 2,
},
},
},
},
],
},
}
```
@ -134,20 +134,20 @@ The following workflow walks through the steps of migrating an actual Vue 2 app
export default {
resolve: {
alias: {
vue: '@vue/compat'
}
vue: '@vue/compat',
},
},
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: {
MODE: 2
}
}
}
})
]
MODE: 2,
},
},
},
}),
],
}
```
@ -207,7 +207,7 @@ import { configureCompat } from 'vue'
// disable compat for certain features
configureCompat({
FEATURE_ID_A: false,
FEATURE_ID_B: false
FEATURE_ID_B: false,
})
```
@ -221,7 +221,7 @@ import { configureCompat } from 'vue'
configureCompat({
MODE: 3,
FEATURE_ID_A: true,
FEATURE_ID_B: true
FEATURE_ID_B: true,
})
```
@ -233,8 +233,8 @@ A component can use the `compatConfig` option, which expects the same options as
export default {
compatConfig: {
MODE: 3, // opt-in to Vue 3 behavior for this component only
FEATURE_ID_A: true // features can also be toggled at component level
}
FEATURE_ID_A: true, // features can also be toggled at component level
},
// ...
}
```
@ -257,18 +257,18 @@ Features that start with `COMPILER_` are compiler-specific: if you are using the
> Should be fixed upfront or will likely lead to errors
| ID | Type | Description | Docs |
| ------------------------------------- | ---- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| ------------------------------------- | ---- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| GLOBAL_MOUNT_CONTAINER | ⨂ | Mounted application does not replace the element it's mounted to | [link](https://v3-migration.vuejs.org/breaking-changes/mount-changes.html) |
| CONFIG_DEVTOOLS | ⨂ | production devtools is now a build-time flag | [link](https://github.com/vuejs/core/tree/main/packages/vue#bundler-build-feature-flags) |
| COMPILER_V_IF_V_FOR_PRECEDENCE | ⨂ | `v-if` and `v-for` precedence when used on the same element has changed | [link](https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html) |
| COMPILER_V_IF_SAME_KEY | ⨂ | `v-if` branches can no longer have the same key | [link](https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#on-conditional-branches) |
| COMPILER_V_FOR_TEMPLATE_KEY_PLACEMENT | ⨂ | `<template v-for>` key should now be placed on `<template>` | [link](https://v3-migration.vuejs.org/breaking-changes/key-attribute.html#with-template-v-for) |
| COMPILER_SFC_FUNCTIONAL | ⨂ | `<template functional>` is no longer supported in SFCs | [link](https://v3-migration.vuejs.org/breaking-changes/functional-components.html#single-file-components-sfcs) | | |
| COMPILER_SFC_FUNCTIONAL | ⨂ | `<template functional>` is no longer supported in SFCs | [link](https://v3-migration.vuejs.org/breaking-changes/functional-components.html#single-file-components-sfcs) |
### Partially Compatible with Caveats
| ID | Type | Description | Docs |
| ------------------------ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| ------------------------ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| CONFIG_IGNORED_ELEMENTS | ◐ | `config.ignoredElements` is now `config.compilerOptions.isCustomElement` (only in browser compiler build). If using build setup, `isCustomElement` must be passed via build configuration. | [link](https://v3-migration.vuejs.org/breaking-changes/global-api.html#config-ignoredelements-is-now-config-iscustomelement) |
| COMPILER_INLINE_TEMPLATE | ◐ | `inline-template` removed (compat only supported in browser compiler build) | [link](https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute.html) |
| PROPS_DEFAULT_THIS | ◐ | props default factory no longer have access to `this` (in compat mode, `this` is not a real instance - it only exposes props, `$options` and injections) | [link](https://v3-migration.vuejs.org/breaking-changes/props-default-this.html) |
@ -280,13 +280,13 @@ Features that start with `COMPILER_` are compiler-specific: if you are using the
### Compat only (no warning)
| ID | Type | Description | Docs |
| ------------------ | ---- | ------------------------------------- | ---------------------------------------- |
| ------------------ | ---- | -------------------------------------- | ----------------------------------------------------------------------- |
| TRANSITION_CLASSES | ⭘ | Transition enter/leave classes changed | [link](https://v3-migration.vuejs.org/breaking-changes/transition.html) |
### Fully Compatible
| ID | Type | Description | Docs |
| ---------------------------- | ---- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| ---------------------------- | ---- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| GLOBAL_MOUNT | ✔ | new Vue() -> createApp | [link](https://v3-migration.vuejs.org/breaking-changes/global-api.html#mounting-app-instance) |
| GLOBAL_EXTEND | ✔ | Vue.extend removed (use `defineComponent` or `extends` option) | [link](https://v3-migration.vuejs.org/breaking-changes/global-api.html#vue-extend-replaced-by-definecomponent) |
| GLOBAL_PROTOTYPE | ✔ | `Vue.prototype` -> `app.config.globalProperties` | [link](https://v3-migration.vuejs.org/breaking-changes/global-api.html#vue-prototype-replaced-by-config-globalproperties) |

View File

@ -5,6 +5,7 @@
### From CDN or without a Bundler
- **`vue(.runtime).global(.prod).js`**:
- For direct use via `<script src="...">` in the browser. Exposes the `Vue` global.
- Note that global builds are not [UMD](https://github.com/umdjs/umd) builds. They are built as [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and is only meant for direct use via `<script src="...">`.
- In-browser template compilation:
@ -38,10 +39,12 @@
`esm-bundler` builds of Vue expose global feature flags that can be overwritten at compile time:
- `__VUE_OPTIONS_API__`
- Default: `true`
- Enable / disable Options API support
- `__VUE_PROD_DEVTOOLS__`
- Default: `false`
- Enable / disable devtools support in production

View File

@ -10,9 +10,14 @@
-webkit-transition: -webkit-transform 50ms ease;
transition: transform 50ms ease;
}
.v-appear, .v-enter, .v-leave-active,
.test-appear, .test-enter, .test-leave-active,
.hello, .bye.active,
.v-appear,
.v-enter,
.v-leave-active,
.test-appear,
.test-enter,
.test-leave-active,
.hello,
.bye.active,
.changed-enter {
opacity: 0;
}
@ -33,19 +38,35 @@
-webkit-animation: test-leave 100ms;
}
@keyframes test-enter {
from { opacity: 0 }
to { opacity: 1 }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes test-enter {
from { opacity: 0 }
to { opacity: 1 }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes test-leave {
from { opacity: 1 }
to { opacity: 0 }
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@-webkit-keyframes test-leave {
from { opacity: 1 }
to { opacity: 0 }
from {
opacity: 1;
}
to {
opacity: 0;
}
}
</style>

View File

@ -3,32 +3,41 @@
<div id="demo">
<h1>Latest Vue.js Commits</h1>
<template v-for="branch in branches">
<input type="radio"
<input
type="radio"
:id="branch"
:value="branch"
name="branch"
v-model="currentBranch">
v-model="currentBranch"
/>
<label :for="branch">{{ branch }}</label>
</template>
<p>vuejs/core@{{ currentBranch }}</p>
<ul>
<li v-for="{ html_url, sha, author, commit } in commits">
<a :href="html_url" target="_blank" class="commit">{{ sha.slice(0, 7) }}</a>
- <span class="message">{{ truncate(commit.message) }}</span><br>
by <span class="author"><a :href="author.html_url" target="_blank">{{ commit.author.name }}</a></span>
<a :href="html_url" target="_blank" class="commit"
>{{ sha.slice(0, 7) }}</a
>
- <span class="message">{{ truncate(commit.message) }}</span><br />
by
<span class="author"
><a :href="author.html_url" target="_blank"
>{{ commit.author.name }}</a
></span
>
at <span class="date">{{ formatDate(commit.author.date) }}</span>
</li>
</ul>
</div>
<script>
const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
Vue.createApp({
Vue.createApp({
data: () => ({
branches: ['main', 'v2-compat'],
currentBranch: 'main',
commits: null
commits: null,
}),
created() {
@ -36,7 +45,7 @@ Vue.createApp({
},
watch: {
currentBranch: 'fetchData'
currentBranch: 'fetchData',
},
methods: {
@ -53,9 +62,9 @@ Vue.createApp({
},
formatDate(v) {
return v.replace(/T|Z/g, ' ')
}
}
}).mount('#demo')
},
},
}).mount('#demo')
</script>
<style>
@ -70,7 +79,8 @@ Vue.createApp({
line-height: 1.5em;
margin-bottom: 20px;
}
.author, .date {
.author,
.date {
font-weight: bold;
}
</style>

View File

@ -26,17 +26,17 @@
</script>
<!-- DemoGrid component script -->
<script>
const DemoGrid = {
const DemoGrid = {
template: '#grid-template',
props: {
data: Array,
columns: Array,
filterKey: String
filterKey: String,
},
data() {
return {
sortKey: '',
sortOrders: this.columns.reduce((o, key) => (o[key] = 1, o), {})
sortOrders: this.columns.reduce((o, key) => ((o[key] = 1), o), {}),
}
},
computed: {
@ -60,7 +60,7 @@ const DemoGrid = {
})
}
return data
}
},
},
methods: {
sortBy(key) {
@ -69,27 +69,22 @@ const DemoGrid = {
},
capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
},
},
}
}
}
</script>
<!-- App template (in DOM) -->
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
<form id="search">Search <input name="query" v-model="searchQuery" /></form>
<demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery">
</demo-grid>
</div>
<!-- App script -->
<script>
Vue.createApp({
Vue.createApp({
components: {
DemoGrid
DemoGrid,
},
data: () => ({
searchQuery: '',
@ -98,70 +93,74 @@ Vue.createApp({
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
})
}).mount('#demo')
{ name: 'Jet Li', power: 8000 },
],
}),
}).mount('#demo')
</script>
<style>
body {
font-family: Helvetica Neue, Arial, sans-serif;
body {
font-family:
Helvetica Neue,
Arial,
sans-serif;
font-size: 14px;
color: #444;
}
}
table {
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
}
th {
th {
background-color: #42b983;
color: rgba(255,255,255,0.66);
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 {
td {
background-color: #f9f9f9;
}
}
th, td {
th,
td {
min-width: 120px;
padding: 10px 20px;
}
}
th.active {
th.active {
color: #fff;
}
}
th.active .arrow {
th.active .arrow {
opacity: 1;
}
}
.arrow {
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
}
.arrow.asc {
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
}
.arrow.dsc {
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}
}
</style>

View File

@ -8,32 +8,35 @@
</div>
<script>
Vue.createApp({
Vue.createApp({
data: () => ({
input: '# hello'
input: '# hello',
}),
computed: {
compiledMarkdown() {
return marked.marked(this.input, { sanitize: true })
}
},
},
methods: {
update: _.debounce(function (e) {
this.input = e.target.value
}, 50)
}
}).mount('#editor')
}, 50),
},
}).mount('#editor')
</script>
<style>
html, body, #editor {
html,
body,
#editor {
margin: 0;
height: 100%;
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #333;
}
}
textarea, #editor div {
textarea,
#editor div {
display: inline-block;
overflow: auto;
width: 50%;
@ -43,9 +46,9 @@ textarea, #editor div {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 20px;
}
}
textarea {
textarea {
border: none;
border-right: 1px solid #ccc;
resize: none;
@ -54,9 +57,9 @@ textarea {
font-size: 14px;
font-family: 'Monaco', courier, monospace;
padding: 20px;
}
}
code {
code {
color: #f66;
}
}
</style>

View File

@ -1,37 +1,33 @@
<script src="../../dist/vue.global.js"></script>
<script>
// math helper...
function valueToPoint (value, index, total) {
// math helper...
function valueToPoint(value, index, total) {
var x = 0
var y = -value * 0.8
var angle = Math.PI * 2 / total * index
var angle = ((Math.PI * 2) / total) * index
var cos = Math.cos(angle)
var sin = Math.sin(angle)
var tx = x * cos - y * sin + 100
var ty = x * sin + y * cos + 100
return {
x: tx,
y: ty
y: ty,
}
}
}
const AxisLabel = {
const AxisLabel = {
template: '<text :x="point.x" :y="point.y">{{stat.label}}</text>',
props: {
stat: Object,
index: Number,
total: Number
total: Number,
},
computed: {
point: function () {
return valueToPoint(
+this.stat.value + 10,
this.index,
this.total
)
return valueToPoint(+this.stat.value + 10, this.index, this.total)
},
},
}
}
}
</script>
<!-- template for the polygraph component. -->
@ -49,23 +45,25 @@ const AxisLabel = {
</script>
<script>
const Polygraph = {
const Polygraph = {
props: ['stats'],
template: '#polygraph-template',
computed: {
// a computed property for the polygon's points
points() {
const total = this.stats.length
return this.stats.map((stat, i) => {
return this.stats
.map((stat, i) => {
const point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
}
})
.join(' ')
},
},
components: {
AxisLabel
AxisLabel,
},
}
}
</script>
<!-- demo root element -->
@ -77,34 +75,34 @@ const Polygraph = {
<!-- controls -->
<div v-for="stat in stats">
<label>{{stat.label}}</label>
<input type="range" v-model="stat.value" min="0" max="100">
<input type="range" v-model="stat.value" min="0" max="100" />
<span>{{stat.value}}</span>
<button @click="remove(stat)" class="remove">X</button>
</div>
<form id="add">
<input name="newlabel" v-model="newLabel">
<input name="newlabel" v-model="newLabel" />
<button @click="add">Add a Stat</button>
</form>
<pre id="raw">{{ stats }}</pre>
</div>
<script>
const globalStats = [
const globalStats = [
{ label: 'A', value: 100 },
{ label: 'B', value: 100 },
{ label: 'C', value: 100 },
{ label: 'D', value: 100 },
{ label: 'E', value: 100 },
{ label: 'F', value: 100 }
]
{ label: 'F', value: 100 },
]
Vue.createApp({
Vue.createApp({
components: {
Polygraph
Polygraph,
},
data: () => ({
newLabel: '',
stats: globalStats
stats: globalStats,
}),
methods: {
add(e) {
@ -112,7 +110,7 @@ Vue.createApp({
if (!this.newLabel) return
this.stats.push({
label: this.newLabel,
value: 100
value: 100,
})
this.newLabel = ''
},
@ -120,43 +118,49 @@ Vue.createApp({
if (this.stats.length > 3) {
this.stats.splice(this.stats.indexOf(stat), 1)
} else {
alert('Can\'t delete more!')
alert("Can't delete more!")
}
}
}
}).mount('#demo')
},
},
}).mount('#demo')
</script>
<style>
body {
font-family: Helvetica Neue, Arial, sans-serif;
}
body {
font-family:
Helvetica Neue,
Arial,
sans-serif;
}
polygon {
polygon {
fill: #42b983;
opacity: .75;
}
opacity: 0.75;
}
circle {
circle {
fill: transparent;
stroke: #999;
}
}
text {
font-family: Helvetica Neue, Arial, sans-serif;
text {
font-family:
Helvetica Neue,
Arial,
sans-serif;
font-size: 10px;
fill: #666;
}
}
label {
label {
display: inline-block;
margin-left: 10px;
width: 20px;
}
}
#raw {
#raw {
position: absolute;
top: 0;
left: 300px;
}
}
</style>

View File

@ -1,49 +1,81 @@
<script src="../../dist/vue.global.js"></script>
<link rel="stylesheet" href="../../../../node_modules/todomvc-app-css/index.css">
<link
rel="stylesheet"
href="../../../../node_modules/todomvc-app-css/index.css"
/>
<div id="app">
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo"
autofocus autocomplete="off"
<input
class="new-todo"
autofocus
autocomplete="off"
placeholder="What needs to be done?"
v-model="newTodo"
@keyup.enter="addTodo">
@keyup.enter="addTodo"
/>
</header>
<section class="main" v-show="todos.length">
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="allDone">
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-model="allDone"
/>
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<li v-for="todo in filteredTodos"
<li
v-for="todo in filteredTodos"
class="todo"
:key="todo.id"
:class="{ completed: todo.completed, editing: todo === editedTodo }">
:class="{ completed: todo.completed, editing: todo === editedTodo }"
>
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed">
<input class="toggle" type="checkbox" v-model="todo.completed" />
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
<input class="edit" type="text"
<input
class="edit"
type="text"
v-model="todo.title"
v-todo-focus="todo === editedTodo"
@blur="doneEdit(todo)"
@keyup.enter="doneEdit(todo)"
@keyup.escape="cancelEdit(todo)"
>
/>
</li>
</ul>
</section>
<footer class="footer" v-show="todos.length">
<span class="todo-count">
<strong>{{ remaining }}</strong> <span>{{ pluralize(remaining) }} left</span>
<strong>{{ remaining }}</strong>
<span>{{ pluralize(remaining) }} left</span>
</span>
<ul class="filters">
<li><a href="#/all" :class="{ selected: visibility === 'all' }">All</a></li>
<li><a href="#/active" :class="{ selected: visibility === 'active' }">Active</a></li>
<li><a href="#/completed" :class="{ selected: visibility === 'completed' }">Completed</a></li>
<li>
<a href="#/all" :class="{ selected: visibility === 'all' }">All</a>
</li>
<li>
<a href="#/active" :class="{ selected: visibility === 'active' }"
>Active</a
>
</li>
<li>
<a
href="#/completed"
:class="{ selected: visibility === 'completed' }"
>Completed</a
>
</li>
</ul>
<button class="clear-completed" @click="removeCompleted" v-show="todos.length > remaining">
<button
class="clear-completed"
@click="removeCompleted"
v-show="todos.length > remaining"
>
Clear completed
</button>
</footer>
@ -51,8 +83,8 @@
</div>
<script>
const STORAGE_KEY = 'todos-vuejs-3.x'
const todoStorage = {
const STORAGE_KEY = 'todos-vuejs-3.x'
const todoStorage = {
fetch() {
const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
todos.forEach((todo, index) => {
@ -63,15 +95,15 @@ const todoStorage = {
},
save(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
},
}
}
const filters = {
const filters = {
all(todos) {
return todos
},
active(todos) {
return todos.filter((todo) => {
return todos.filter(todo => {
return !todo.completed
})
},
@ -79,16 +111,16 @@ const filters = {
return todos.filter(function (todo) {
return todo.completed
})
},
}
}
Vue.createApp({
Vue.createApp({
// app initial state
data: () => ({
todos: todoStorage.fetch(),
newTodo: '',
editedTodo: null,
visibility: 'all'
visibility: 'all',
}),
// watch todos change for localStorage persistence
@ -97,8 +129,8 @@ Vue.createApp({
handler(todos) {
todoStorage.save(todos)
},
deep: true
}
deep: true,
},
},
mounted() {
@ -121,8 +153,8 @@ Vue.createApp({
this.todos.forEach(function (todo) {
todo.completed = value
})
}
}
},
},
},
// methods that implement data logic.
@ -136,7 +168,7 @@ Vue.createApp({
this.todos.push({
id: todoStorage.uid++,
title: value,
completed: false
completed: false,
})
this.newTodo = ''
},
@ -180,9 +212,9 @@ Vue.createApp({
}
},
pluralize (n) {
pluralize(n) {
return n === 1 ? 'item' : 'items'
}
},
},
directives: {
@ -190,7 +222,7 @@ Vue.createApp({
if (binding.value) {
el.focus()
}
}
}
}).mount('#app')
},
},
}).mount('#app')
</script>

View File

@ -22,22 +22,21 @@
</script>
<!-- item script -->
<script>
const TreeItem = {
const TreeItem = {
name: 'TreeItem', // necessary for self-reference
template: '#item-template',
props: {
model: Object
model: Object,
},
data() {
return {
open: false
open: false,
}
},
computed: {
isFolder() {
return this.model.children &&
this.model.children.length
}
return this.model.children && this.model.children.length
},
},
methods: {
toggle() {
@ -54,11 +53,11 @@ const TreeItem = {
},
addChild() {
this.model.children.push({
name: 'new stuff'
name: 'new stuff',
})
},
},
}
}
}
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
@ -69,7 +68,7 @@ const TreeItem = {
</ul>
<script>
const treeData = {
const treeData = {
name: 'My Tree',
children: [
{ name: 'hello' },
@ -79,33 +78,27 @@ const treeData = {
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
children: [{ name: 'hello' }, { name: 'wat' }],
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
children: [{ name: 'hello' }, { name: 'wat' }],
},
],
},
],
}
]
}
]
}
Vue.createApp({
Vue.createApp({
components: {
TreeItem
TreeItem,
},
data: () => ({
treeData
})
}).mount('#demo')
treeData,
}),
}).mount('#demo')
</script>
<style>

View File

@ -3,36 +3,45 @@
<div id="demo">
<h1>Latest Vue.js Commits</h1>
<template v-for="branch in branches">
<input type="radio"
<input
type="radio"
:id="branch"
:value="branch"
name="branch"
v-model="currentBranch">
v-model="currentBranch"
/>
<label :for="branch">{{ branch }}</label>
</template>
<p>vuejs/core@{{ currentBranch }}</p>
<ul>
<li v-for="{ html_url, sha, author, commit } in commits">
<a :href="html_url" target="_blank" class="commit">{{ sha.slice(0, 7) }}</a>
- <span class="message">{{ truncate(commit.message) }}</span><br>
by <span class="author"><a :href="author.html_url" target="_blank">{{ commit.author.name }}</a></span>
<a :href="html_url" target="_blank" class="commit"
>{{ sha.slice(0, 7) }}</a
>
- <span class="message">{{ truncate(commit.message) }}</span><br />
by
<span class="author"
><a :href="author.html_url" target="_blank"
>{{ commit.author.name }}</a
></span
>
at <span class="date">{{ formatDate(commit.author.date) }}</span>
</li>
</ul>
</div>
<script>
const { createApp, ref, watchEffect } = Vue
const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
const { createApp, ref, watchEffect } = Vue
const API_URL = `https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=`
const truncate = v => {
const truncate = v => {
const newline = v.indexOf('\n')
return newline > 0 ? v.slice(0, newline) : v
}
}
const formatDate = v => v.replace(/T|Z/g, ' ')
const formatDate = v => v.replace(/T|Z/g, ' ')
createApp({
createApp({
setup() {
const currentBranch = ref('main')
const commits = ref(null)
@ -51,10 +60,10 @@ createApp({
currentBranch,
commits,
truncate,
formatDate
formatDate,
}
}
}).mount('#demo')
},
}).mount('#demo')
</script>
<style>
@ -69,7 +78,8 @@ createApp({
line-height: 1.5em;
margin-bottom: 20px;
}
.author, .date {
.author,
.date {
font-weight: bold;
}
</style>

View File

@ -26,21 +26,21 @@
</script>
<!-- DemoGrid component script -->
<script>
const { reactive, computed } = Vue
const { reactive, computed } = Vue
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
const DemoGrid = {
const DemoGrid = {
template: '#grid-template',
props: {
data: Array,
columns: Array,
filterKey: String
filterKey: String,
},
setup(props) {
const state = reactive({
sortKey: '',
sortOrders: props.columns.reduce((o, key) => (o[key] = 1, o), {})
sortOrders: props.columns.reduce((o, key) => ((o[key] = 1), o), {}),
})
const filteredData = computed(() => {
@ -74,28 +74,23 @@ const DemoGrid = {
state,
filteredData,
sortBy,
capitalize
capitalize,
}
},
}
}
</script>
<!-- App template (in DOM) -->
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
<form id="search">Search <input name="query" v-model="searchQuery" /></form>
<demo-grid :data="gridData" :columns="gridColumns" :filter-key="searchQuery">
</demo-grid>
</div>
<!-- App script -->
<script>
Vue.createApp({
Vue.createApp({
components: {
DemoGrid
DemoGrid,
},
data: () => ({
searchQuery: '',
@ -104,70 +99,74 @@ Vue.createApp({
{ name: 'Chuck Norris', power: Infinity },
{ name: 'Bruce Lee', power: 9000 },
{ name: 'Jackie Chan', power: 7000 },
{ name: 'Jet Li', power: 8000 }
]
})
}).mount('#demo')
{ name: 'Jet Li', power: 8000 },
],
}),
}).mount('#demo')
</script>
<style>
body {
font-family: Helvetica Neue, Arial, sans-serif;
body {
font-family:
Helvetica Neue,
Arial,
sans-serif;
font-size: 14px;
color: #444;
}
}
table {
table {
border: 2px solid #42b983;
border-radius: 3px;
background-color: #fff;
}
}
th {
th {
background-color: #42b983;
color: rgba(255,255,255,0.66);
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 {
td {
background-color: #f9f9f9;
}
}
th, td {
th,
td {
min-width: 120px;
padding: 10px 20px;
}
}
th.active {
th.active {
color: #fff;
}
}
th.active .arrow {
th.active .arrow {
opacity: 1;
}
}
.arrow {
.arrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
margin-left: 5px;
opacity: 0.66;
}
}
.arrow.asc {
.arrow.asc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid #fff;
}
}
.arrow.dsc {
.arrow.dsc {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #fff;
}
}
</style>

View File

@ -8,32 +8,39 @@
</div>
<script>
const { ref, computed } = Vue
const { ref, computed } = Vue
Vue.createApp({
Vue.createApp({
setup() {
const input = ref('# hello')
const output = computed(() => marked.marked(input.value, { sanitize: true }))
const update = _.debounce(e => { input.value = e.target.value }, 50)
const output = computed(() =>
marked.marked(input.value, { sanitize: true }),
)
const update = _.debounce(e => {
input.value = e.target.value
}, 50)
return {
input,
output,
update
update,
}
}
}).mount('#editor')
},
}).mount('#editor')
</script>
<style>
html, body, #editor {
html,
body,
#editor {
margin: 0;
height: 100%;
font-family: 'Helvetica Neue', Arial, sans-serif;
color: #333;
}
}
textarea, #editor div {
textarea,
#editor div {
display: inline-block;
overflow: auto;
width: 50%;
@ -43,9 +50,9 @@ textarea, #editor div {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0 20px;
}
}
textarea {
textarea {
border: none;
border-right: 1px solid #ccc;
resize: none;
@ -54,9 +61,9 @@ textarea {
font-size: 14px;
font-family: 'Monaco', courier, monospace;
padding: 20px;
}
}
code {
code {
color: #f66;
}
}
</style>

View File

@ -1,39 +1,37 @@
<script src="../../dist/vue.global.js"></script>
<script>
const { ref, reactive, computed, createApp } = Vue
const { ref, reactive, computed, createApp } = Vue
// math helper...
function valueToPoint (value, index, total) {
// math helper...
function valueToPoint(value, index, total) {
var x = 0
var y = -value * 0.8
var angle = Math.PI * 2 / total * index
var angle = ((Math.PI * 2) / total) * index
var cos = Math.cos(angle)
var sin = Math.sin(angle)
var tx = x * cos - y * sin + 100
var ty = x * sin + y * cos + 100
return {
x: tx,
y: ty
y: ty,
}
}
}
const AxisLabel = {
const AxisLabel = {
template: '<text :x="point.x" :y="point.y">{{stat.label}}</text>',
props: {
stat: Object,
index: Number,
total: Number
total: Number,
},
setup(props) {
return {
point: computed(() => valueToPoint(
+props.stat.value + 10,
props.index,
props.total
))
point: computed(() =>
valueToPoint(+props.stat.value + 10, props.index, props.total),
),
}
},
}
}
</script>
<!-- template for the polygraph component. -->
@ -51,24 +49,26 @@ const AxisLabel = {
</script>
<script>
const Polygraph = {
const Polygraph = {
props: ['stats'],
template: '#polygraph-template',
setup(props) {
return {
points: computed(() => {
const total = props.stats.length
return props.stats.map((stat, i) => {
return props.stats
.map((stat, i) => {
const point = valueToPoint(stat.value, i, total)
return point.x + ',' + point.y
}).join(' ')
})
.join(' ')
}),
}
},
components: {
AxisLabel
AxisLabel,
},
}
}
</script>
<!-- demo root element -->
@ -80,30 +80,30 @@ const Polygraph = {
<!-- controls -->
<div v-for="stat in stats">
<label>{{stat.label}}</label>
<input type="range" v-model="stat.value" min="0" max="100">
<input type="range" v-model="stat.value" min="0" max="100" />
<span>{{stat.value}}</span>
<button @click="remove(stat)" class="remove">X</button>
</div>
<form id="add">
<input name="newlabel" v-model="newLabel">
<input name="newlabel" v-model="newLabel" />
<button @click="add">Add a Stat</button>
</form>
<pre id="raw">{{ stats }}</pre>
</div>
<script>
const globalStats = [
const globalStats = [
{ label: 'A', value: 100 },
{ label: 'B', value: 100 },
{ label: 'C', value: 100 },
{ label: 'D', value: 100 },
{ label: 'E', value: 100 },
{ label: 'F', value: 100 }
]
{ label: 'F', value: 100 },
]
createApp({
createApp({
components: {
Polygraph
Polygraph,
},
setup() {
const newLabel = ref('')
@ -114,7 +114,7 @@ createApp({
if (!newLabel.value) return
stats.push({
label: newLabel.value,
value: 100
value: 100,
})
newLabel.value = ''
}
@ -123,7 +123,7 @@ createApp({
if (stats.length > 3) {
stats.splice(stats.indexOf(stat), 1)
} else {
alert('Can\'t delete more!')
alert("Can't delete more!")
}
}
@ -131,42 +131,48 @@ createApp({
newLabel,
stats,
add,
remove
remove,
}
}
}).mount('#demo')
},
}).mount('#demo')
</script>
<style>
body {
font-family: Helvetica Neue, Arial, sans-serif;
}
body {
font-family:
Helvetica Neue,
Arial,
sans-serif;
}
polygon {
polygon {
fill: #42b983;
opacity: .75;
}
opacity: 0.75;
}
circle {
circle {
fill: transparent;
stroke: #999;
}
}
text {
font-family: Helvetica Neue, Arial, sans-serif;
text {
font-family:
Helvetica Neue,
Arial,
sans-serif;
font-size: 10px;
fill: #666;
}
}
label {
label {
display: inline-block;
margin-left: 10px;
width: 20px;
}
}
#raw {
#raw {
position: absolute;
top: 0;
left: 300px;
}
}
</style>

View File

@ -1,36 +1,51 @@
<script src="../../dist/vue.global.js"></script>
<link rel="stylesheet" href="../../../../node_modules/todomvc-app-css/index.css">
<link
rel="stylesheet"
href="../../../../node_modules/todomvc-app-css/index.css"
/>
<div id="app">
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo"
autofocus autocomplete="off"
<input
class="new-todo"
autofocus
autocomplete="off"
placeholder="What needs to be done?"
v-model="state.newTodo"
@keyup.enter="addTodo">
@keyup.enter="addTodo"
/>
</header>
<section class="main" v-show="state.todos.length">
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="state.allDone">
<input
id="toggle-all"
class="toggle-all"
type="checkbox"
v-model="state.allDone"
/>
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list">
<li v-for="todo in state.filteredTodos"
<li
v-for="todo in state.filteredTodos"
class="todo"
:key="todo.id"
:class="{ completed: todo.completed, editing: todo === state.editedTodo }">
:class="{ completed: todo.completed, editing: todo === state.editedTodo }"
>
<div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed">
<input class="toggle" type="checkbox" v-model="todo.completed" />
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
<input class="edit" type="text"
<input
class="edit"
type="text"
v-model="todo.title"
v-todo-focus="todo === state.editedTodo"
@blur="doneEdit(todo)"
@keyup.enter="doneEdit(todo)"
@keyup.escape="cancelEdit(todo)"
>
/>
</li>
</ul>
</section>
@ -40,12 +55,32 @@
<span>{{ state.remainingText }}</span>
</span>
<ul class="filters">
<li><a href="#/all" :class="{ selected: state.visibility === 'all' }">All</a></li>
<li><a href="#/active" :class="{ selected: state.visibility === 'active' }">Active</a></li>
<li><a href="#/completed" :class="{ selected: state.visibility === 'completed' }">Completed</a></li>
<li>
<a href="#/all" :class="{ selected: state.visibility === 'all' }"
>All</a
>
</li>
<li>
<a
href="#/active"
:class="{ selected: state.visibility === 'active' }"
>Active</a
>
</li>
<li>
<a
href="#/completed"
:class="{ selected: state.visibility === 'completed' }"
>Completed</a
>
</li>
</ul>
<button class="clear-completed" @click="removeCompleted" v-show="state.todos.length > state.remaining">
<button
class="clear-completed"
@click="removeCompleted"
v-show="state.todos.length > state.remaining"
>
Clear completed
</button>
</footer>
@ -53,11 +88,12 @@
</div>
<script>
const { createApp, reactive, computed, watchEffect, onMounted, onUnmounted } = Vue
const { createApp, reactive, computed, watchEffect, onMounted, onUnmounted } =
Vue
const STORAGE_KEY = 'todos-vuejs-3.x'
const todoStorage = {
fetch () {
const STORAGE_KEY = 'todos-vuejs-3.x'
const todoStorage = {
fetch() {
const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
todos.forEach((todo, index) => {
todo.id = index
@ -65,33 +101,33 @@ const todoStorage = {
todoStorage.uid = todos.length
return todos
},
save (todos) {
save(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
},
}
}
const filters = {
all (todos) {
const filters = {
all(todos) {
return todos
},
active (todos) {
return todos.filter((todo) => {
active(todos) {
return todos.filter(todo => {
return !todo.completed
})
},
completed (todos) {
completed(todos) {
return todos.filter(function (todo) {
return todo.completed
})
},
}
}
function pluralize (n) {
function pluralize(n) {
return n === 1 ? 'item' : 'items'
}
}
createApp({
setup () {
createApp({
setup() {
const state = reactive({
todos: todoStorage.fetch(),
editedTodo: null,
@ -112,11 +148,11 @@ createApp({
return state.remaining === 0
},
set: function (value) {
state.todos.forEach((todo) => {
state.todos.forEach(todo => {
todo.completed = value
})
}
})
},
}),
})
watchEffect(() => {
@ -132,7 +168,7 @@ createApp({
window.removeEventListener('hashchange', onHashChange)
})
function onHashChange () {
function onHashChange() {
const visibility = window.location.hash.replace(/#\/?/, '')
if (filters[visibility]) {
state.visibility = visibility
@ -142,7 +178,7 @@ createApp({
}
}
function addTodo () {
function addTodo() {
const value = state.newTodo && state.newTodo.trim()
if (!value) {
return
@ -150,21 +186,21 @@ createApp({
state.todos.push({
id: todoStorage.uid++,
title: value,
completed: false
completed: false,
})
state.newTodo = ''
}
function removeTodo (todo) {
function removeTodo(todo) {
state.todos.splice(state.todos.indexOf(todo), 1)
}
function editTodo (todo) {
function editTodo(todo) {
state.beforeEditCache = todo.title
state.editedTodo = todo
}
function doneEdit (todo) {
function doneEdit(todo) {
if (!state.editedTodo) {
return
}
@ -175,12 +211,12 @@ createApp({
}
}
function cancelEdit (todo) {
function cancelEdit(todo) {
state.editedTodo = null
todo.title = state.beforeEditCache
}
function removeCompleted () {
function removeCompleted() {
state.todos = filters.active(state.todos)
}
@ -191,7 +227,7 @@ createApp({
editTodo,
doneEdit,
cancelEdit,
removeCompleted
removeCompleted,
}
},
@ -200,7 +236,7 @@ createApp({
if (value) {
el.focus()
}
}
}
}).mount('#app')
},
},
}).mount('#app')
</script>

View File

@ -22,20 +22,20 @@
</script>
<!-- item script -->
<script>
const { reactive, computed, toRefs } = Vue
const { reactive, computed, toRefs } = Vue
const TreeItem = {
const TreeItem = {
name: 'TreeItem', // necessary for self-reference
template: '#item-template',
props: {
model: Object
model: Object,
},
setup(props) {
const state = reactive({
open: false,
isFolder: computed(() => {
return props.model.children && props.model.children.length
})
}),
})
function toggle() {
@ -58,10 +58,10 @@ const TreeItem = {
...toRefs(state),
toggle,
changeType,
addChild
addChild,
}
},
}
}
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
@ -72,7 +72,7 @@ const TreeItem = {
</ul>
<script>
const treeData = {
const treeData = {
name: 'My Tree',
children: [
{ name: 'hello' },
@ -82,33 +82,27 @@ const treeData = {
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
children: [{ name: 'hello' }, { name: 'wat' }],
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
children: [{ name: 'hello' }, { name: 'wat' }],
},
],
},
],
}
]
}
]
}
Vue.createApp({
Vue.createApp({
components: {
TreeItem
TreeItem,
},
data: () => ({
treeData
})
}).mount('#demo')
treeData,
}),
}).mount('#demo')
</script>
<style>

View File

@ -6,78 +6,83 @@
<button @click="reset">reset</button>
<button @click="shuffle">shuffle</button>
<transition-group tag="ul" name="fade" class="container">
<item v-for="item in items"
<item
v-for="item in items"
class="item"
:msg="item"
:key="item"
@rm="remove(item)">
@rm="remove(item)"
>
</item>
</transition-group>
</div>
<script>
const getInitialItems = () => [1, 2, 3, 4, 5]
let id = getInitialItems().length + 1
const getInitialItems = () => [1, 2, 3, 4, 5]
let id = getInitialItems().length + 1
const Item = {
const Item = {
props: ['msg'],
template: `<div>{{ msg }} <button @click="$emit('rm')">x</button></div>`
}
template: `<div>{{ msg }} <button @click="$emit('rm')">x</button></div>`,
}
Vue.createApp({
Vue.createApp({
components: {
Item
Item,
},
data() {
return {
items: getInitialItems()
items: getInitialItems(),
}
},
methods: {
insert () {
insert() {
const i = Math.round(Math.random() * this.items.length)
this.items.splice(i, 0, id++)
},
reset () {
reset() {
this.items = getInitialItems()
},
shuffle () {
shuffle() {
this.items = _.shuffle(this.items)
},
remove (item) {
remove(item) {
const i = this.items.indexOf(item)
if (i > -1) {
this.items.splice(i, 1)
}
}
}
}).mount('#app')
},
},
}).mount('#app')
</script>
<style>
.container {
.container {
position: relative;
padding: 0;
}
.item {
}
.item {
width: 100%;
height: 30px;
background-color: #f3f3f3;
border: 1px solid #666;
box-sizing: border-box;
}
/* 1. declare transition */
.fade-move, .fade-enter-active, .fade-leave-active {
transition: all .5s cubic-bezier(.55,0,.1,1);
}
/* 2. declare enter from and leave to state */
.fade-enter-from, .fade-leave-to {
}
/* 1. declare transition */
.fade-move,
.fade-enter-active,
.fade-leave-active {
transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
}
/* 2. declare enter from and leave to state */
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scaleY(0.01) translate(30px, 0);
}
/* 3. ensure leaving items are taken out of layout flow so that moving
}
/* 3. ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.fade-leave-active {
.fade-leave-active {
position: absolute;
}
}
</style>

View File

@ -33,10 +33,10 @@
</transition>
</script>
<script>
const Modal = {
const Modal = {
template: '#modal-template',
props: ['show']
}
props: ['show'],
}
</script>
<!-- modal container that lives outside of app root -->
@ -56,57 +56,57 @@ const Modal = {
</div>
<script>
Vue.createApp({
Vue.createApp({
components: { Modal },
data: () => ({
showModal: false
})
}).mount('#app')
showModal: false,
}),
}).mount('#app')
</script>
<style>
.modal-mask {
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
background-color: rgba(0, 0, 0, 0.5);
display: table;
transition: opacity .3s ease;
}
transition: opacity 0.3s ease;
}
.modal-wrapper {
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
}
.modal-container {
.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, .33);
transition: all .3s ease;
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 {
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
}
.modal-body {
.modal-body {
margin: 20px 0;
}
}
.modal-default-button {
.modal-default-button {
float: right;
}
}
/*
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
@ -115,17 +115,17 @@ Vue.createApp({
* these styles.
*/
.modal-enter-from {
.modal-enter-from {
opacity: 0;
}
}
.modal-leave-to {
.modal-leave-to {
opacity: 0;
}
}
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
.modal-enter-from .modal-container,
.modal-leave-to .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
}
</style>