]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: add a few 2.x examples
authorEvan You <yyx990803@gmail.com>
Mon, 2 Dec 2019 04:54:32 +0000 (23:54 -0500)
committerEvan You <yyx990803@gmail.com>
Mon, 2 Dec 2019 04:54:32 +0000 (23:54 -0500)
packages/vue/examples/classic/commits.html [new file with mode: 0644]
packages/vue/examples/classic/grid.html [new file with mode: 0644]
packages/vue/examples/classic/svg.html [new file with mode: 0644]
packages/vue/examples/classic/todomvc.html [moved from packages/vue/examples/todomvc-classic.html with 99% similarity]
packages/vue/examples/composition/commits.html [new file with mode: 0644]
packages/vue/examples/composition/grid.html [new file with mode: 0644]
packages/vue/examples/composition/svg.html [new file with mode: 0644]
packages/vue/examples/composition/todomvc.html [moved from packages/vue/examples/todomvc-composition.html with 99% similarity]

diff --git a/packages/vue/examples/classic/commits.html b/packages/vue/examples/classic/commits.html
new file mode 100644 (file)
index 0000000..d88f0e2
--- /dev/null
@@ -0,0 +1,78 @@
+<script src="../../dist/vue.global.js"></script>
+
+<div id="demo">
+  <h1>Latest Vue.js Commits</h1>
+  <template v-for="branch in branches">
+    <input type="radio"
+      :id="branch"
+      :value="branch"
+      name="branch"
+      v-model="currentBranch">
+    <label :for="branch">{{ branch }}</label>
+  </template>
+  <p>vuejs/vue@{{ 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>
+      at <span class="date">{{ formatDate(commit.author.date) }}</span>
+    </li>
+  </ul>
+</div>
+
+<script>
+const API_URL = `https://api.github.com/repos/vuejs/vue-next/commits?per_page=3&sha=`
+
+const App = {
+  data: {
+    branches: ['master', 'sync'],
+    currentBranch: 'master',
+    commits: null
+  },
+
+  created() {
+    this.fetchData()
+  },
+
+  watch: {
+    currentBranch: 'fetchData'
+  },
+
+  methods: {
+    fetchData() {
+      fetch(`${API_URL}${this.currentBranch}`)
+        .then(res => res.json())
+        .then(data => {
+          this.commits = data
+        })
+    },
+    truncate(v) {
+      const newline = v.indexOf('\n')
+      return newline > 0 ? v.slice(0, newline) : v
+    },
+    formatDate(v) {
+      return v.replace(/T|Z/g, ' ')
+    }
+  }
+}
+
+Vue.createApp().mount(App, '#demo')
+</script>
+
+<style>
+  #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;
+  }
+</style>
diff --git a/packages/vue/examples/classic/grid.html b/packages/vue/examples/classic/grid.html
new file mode 100644 (file)
index 0000000..b32c96b
--- /dev/null
@@ -0,0 +1,169 @@
+<script src="../../dist/vue.global.js"></script>
+
+<!-- DemoGrid component template -->
+<script type="text/x-template" id="grid-template">
+  <table v-if="filteredData.length">
+    <thead>
+      <tr>
+        <th v-for="key in columns"
+          @click="sortBy(key)"
+          :class="{ active: sortKey == key }">
+          {{ capitalize(key) }}
+          <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr v-for="entry in filteredData">
+        <td v-for="key in columns">
+          {{entry[key]}}
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <p v-else>No matches found.</p>
+</script>
+<!-- DemoGrid component script -->
+<script>
+const DemoGrid = {
+  template: '#grid-template',
+  props: {
+    data: Array,
+    columns: Array,
+    filterKey: String
+  },
+  data() {
+    return {
+      sortKey: '',
+      sortOrders: this.columns.reduce((o, key) => (o[key] = 1, o), {})
+    }
+  },
+  computed: {
+    filteredData() {
+      const sortKey = this.sortKey
+      const filterKey = this.filterKey && this.filterKey.toLowerCase()
+      const order = this.sortOrders[sortKey] || 1
+      let data = this.data
+      if (filterKey) {
+        data = data.filter(row => {
+          return Object.keys(row).some(key => {
+            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
+          })
+        })
+      }
+      if (sortKey) {
+        data = data.slice().sort((a, b) => {
+          a = a[sortKey]
+          b = b[sortKey]
+          return (a === b ? 0 : a > b ? 1 : -1) * order
+        })
+      }
+      return data
+    }
+  },
+  methods: {
+    sortBy(key) {
+      this.sortKey = key
+      this.sortOrders[key] = this.sortOrders[key] * -1
+    },
+    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">
+  </demo-grid>
+</div>
+<!-- App script -->
+<script>
+const App = {
+  components: {
+    DemoGrid
+  },
+  data: {
+    searchQuery: '',
+    gridColumns: ['name', 'power'],
+    gridData: [
+      { name: 'Chuck Norris', power: Infinity },
+      { name: 'Bruce Lee', power: 9000 },
+      { name: 'Jackie Chan', power: 7000 },
+      { name: 'Jet Li', power: 8000 }
+    ]
+  }
+}
+
+Vue.createApp().mount(App, '#demo')
+</script>
+
+<style>
+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;
+}
+</style>
diff --git a/packages/vue/examples/classic/svg.html b/packages/vue/examples/classic/svg.html
new file mode 100644 (file)
index 0000000..6be9add
--- /dev/null
@@ -0,0 +1,177 @@
+<script src="../../dist/vue.global.js"></script>
+<script>
+// math helper...
+function valueToPoint (value, index, total) {
+  var x     = 0
+  var y     = -value * 0.8
+  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
+  }
+}
+
+const AxisLabel = {
+  template: '<text :x="point.x" :y="point.y">{{stat.label}}</text>',
+  props: {
+    stat: Object,
+    index: Number,
+    total: Number
+  },
+  computed: {
+    point: function () {
+      return valueToPoint(
+        +this.stat.value + 10,
+        this.index,
+        this.total
+      )
+    }
+  }
+}
+</script>
+
+<!-- template for the polygraph component. -->
+<script type="text/x-template" id="polygraph-template">
+  <g>
+    <polygon :points="points"></polygon>
+    <circle cx="100" cy="100" r="80"></circle>
+    <axis-label
+      v-for="(stat, index) in stats"
+      :stat="stat"
+      :index="index"
+      :total="stats.length">
+    </axis-label>
+  </g>
+</script>
+
+<script>
+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) => {
+        const point = valueToPoint(stat.value, i, total)
+        return point.x + ',' + point.y
+      }).join(' ')
+    }
+  },
+  components: {
+    AxisLabel
+  }
+}
+
+// math helper...
+function valueToPoint (value, index, total) {
+  var x     = 0
+  var y     = -value * 0.8
+  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
+  }
+}
+</script>
+
+<!-- demo root element -->
+<div id="demo">
+  <!-- Use the polygraph component -->
+  <svg width="200" height="200">
+    <polygraph :stats="stats"></polygraph>
+  </svg>
+  <!-- controls -->
+  <div v-for="stat in stats">
+    <label>{{stat.label}}</label>
+    <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">
+    <button @click="add">Add a Stat</button>
+  </form>
+  <pre id="raw">{{ stats }}</pre>
+</div>
+
+<script>
+const App = {
+  components: {
+    Polygraph
+  },
+  data: {
+    newLabel: '',
+    stats: [
+      { label: 'A', value: 100 },
+      { label: 'B', value: 100 },
+      { label: 'C', value: 100 },
+      { label: 'D', value: 100 },
+      { label: 'E', value: 100 },
+      { label: 'F', value: 100 }
+    ]
+  },
+  methods: {
+    add(e) {
+      e.preventDefault()
+      if (!this.newLabel) return
+      this.stats.push({
+        label: this.newLabel,
+        value: 100
+      })
+      this.newLabel = ''
+    },
+    remove(stat) {
+      if (this.stats.length > 3) {
+        this.stats.splice(this.stats.indexOf(stat), 1)
+      } else {
+        alert('Can\'t delete more!')
+      }
+    }
+  }
+}
+
+Vue.createApp().mount(App, '#demo')
+</script>
+
+<style>
+body {
+    font-family: Helvetica Neue, Arial, sans-serif;
+}
+
+polygon {
+    fill: #42b983;
+    opacity: .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;
+}
+</style>
similarity index 99%
rename from packages/vue/examples/todomvc-classic.html
rename to packages/vue/examples/classic/todomvc.html
index 47a6b70b16443418f273f21873ce7b320078629a..092f6b36cb38116a469bc1e02421b9f73cfc0afe 100644 (file)
@@ -1,4 +1,4 @@
-<script src="../dist/vue.global.js"></script>
+<script src="../../dist/vue.global.js"></script>
 <link rel="stylesheet" href="https://unpkg.com/todomvc-app-css/index.css">
 
 <div id="app">
diff --git a/packages/vue/examples/composition/commits.html b/packages/vue/examples/composition/commits.html
new file mode 100644 (file)
index 0000000..5212f79
--- /dev/null
@@ -0,0 +1,74 @@
+<script src="../../dist/vue.global.js"></script>
+
+<div id="demo">
+  <h1>Latest Vue.js Commits</h1>
+  <template v-for="branch in branches">
+    <input type="radio"
+      :id="branch"
+      :value="branch"
+      name="branch"
+      v-model="currentBranch">
+    <label :for="branch">{{ branch }}</label>
+  </template>
+  <p>vuejs/vue@{{ 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>
+      at <span class="date">{{ formatDate(commit.author.date) }}</span>
+    </li>
+  </ul>
+</div>
+
+<script>
+const { createApp, ref, watch } = Vue
+const API_URL = `https://api.github.com/repos/vuejs/vue-next/commits?per_page=3&sha=`
+
+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 App = {
+  setup() {
+    const currentBranch = ref('master')
+    const commits = ref(null)
+
+    watch(() => {
+      fetch(`${API_URL}${currentBranch.value}`)
+        .then(res => res.json())
+        .then(data => { commits.value = data })
+    })
+
+    return {
+      branches: ['master', 'sync'],
+      currentBranch,
+      commits,
+      truncate,
+      formatDate
+    }
+  }
+}
+
+createApp().mount(App, '#demo')
+</script>
+
+<style>
+  #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;
+  }
+</style>
diff --git a/packages/vue/examples/composition/grid.html b/packages/vue/examples/composition/grid.html
new file mode 100644 (file)
index 0000000..f865ab9
--- /dev/null
@@ -0,0 +1,175 @@
+<script src="../../dist/vue.global.js"></script>
+
+<!-- DemoGrid component template -->
+<script type="text/x-template" id="grid-template">
+  <table v-if="filteredData.length">
+    <thead>
+      <tr>
+        <th v-for="key in columns"
+          @click="sortBy(key)"
+          :class="{ active: sortKey == key }">
+          {{ capitalize(key) }}
+          <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
+          </span>
+        </th>
+      </tr>
+    </thead>
+    <tbody>
+      <tr v-for="entry in filteredData">
+        <td v-for="key in columns">
+          {{entry[key]}}
+        </td>
+      </tr>
+    </tbody>
+  </table>
+  <p v-else>No matches found.</p>
+</script>
+<!-- DemoGrid component script -->
+<script>
+const { reactive, computed } = Vue
+
+const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
+
+const DemoGrid = {
+  template: '#grid-template',
+  props: {
+    data: Array,
+    columns: Array,
+    filterKey: String
+  },
+  setup(props) {
+    const state = reactive({
+      sortKey: '',
+      sortOrders: props.columns.reduce((o, key) => (o[key] = 1, o), {})
+    })
+
+    const filteredData = computed(() => {
+      let { data, filterKey } = props
+      if (filterKey) {
+        filterKey = filterKey.toLowerCase()
+        data = data.filter(row => {
+          return Object.keys(row).some(key => {
+            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
+          })
+        })
+      }
+      const { sortKey } = state
+      if (sortKey) {
+        const order = state.sortOrders[sortKey]
+        data = data.slice().sort((a, b) => {
+          a = a[sortKey]
+          b = b[sortKey]
+          return (a === b ? 0 : a > b ? 1 : -1) * order
+        })
+      }
+      return data
+    })
+
+    function sortBy(key) {
+      state.sortKey = key
+      state.sortOrders[key] *= -1
+    }
+
+    return {
+      ...state,
+      filteredData,
+      sortBy,
+      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">
+  </demo-grid>
+</div>
+<!-- App script -->
+<script>
+const App = {
+  components: {
+    DemoGrid
+  },
+  data: {
+    searchQuery: '',
+    gridColumns: ['name', 'power'],
+    gridData: [
+      { name: 'Chuck Norris', power: Infinity },
+      { name: 'Bruce Lee', power: 9000 },
+      { name: 'Jackie Chan', power: 7000 },
+      { name: 'Jet Li', power: 8000 }
+    ]
+  }
+}
+
+Vue.createApp().mount(App, '#demo')
+</script>
+
+<style>
+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;
+}
+</style>
diff --git a/packages/vue/examples/composition/svg.html b/packages/vue/examples/composition/svg.html
new file mode 100644 (file)
index 0000000..f4c2f65
--- /dev/null
@@ -0,0 +1,170 @@
+<script src="../../dist/vue.global.js"></script>
+<script>
+// math helper...
+function valueToPoint (value, index, total) {
+  var x     = 0
+  var y     = -value * 0.8
+  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
+  }
+}
+
+const AxisLabel = {
+  template: '<text :x="point.x" :y="point.y">{{stat.label}}</text>',
+  props: {
+    stat: Object,
+    index: Number,
+    total: Number
+  },
+  setup(props) {
+    return {
+      point: Vue.computed(() => valueToPoint(
+        +props.stat.value + 10,
+        props.index,
+        props.total
+      ))
+    }
+  }
+}
+</script>
+
+<!-- template for the polygraph component. -->
+<script type="text/x-template" id="polygraph-template">
+  <g>
+    <polygon :points="points"></polygon>
+    <circle cx="100" cy="100" r="80"></circle>
+    <axis-label
+      v-for="(stat, index) in stats"
+      :stat="stat"
+      :index="index"
+      :total="stats.length">
+    </axis-label>
+  </g>
+</script>
+
+<script>
+const Polygraph = {
+  props: ['stats'],
+  template: '#polygraph-template',
+  setup(props) {
+    return {
+      points: Vue.computed(() => {
+        const total = props.stats.length
+        return props.stats.map((stat, i) => {
+          const point = valueToPoint(stat.value, i, total)
+          return point.x + ',' + point.y
+        }).join(' ')
+      })
+    }
+  },
+  components: {
+    AxisLabel
+  }
+}
+</script>
+
+<!-- demo root element -->
+<div id="demo">
+  <!-- Use the polygraph component -->
+  <svg width="200" height="200">
+    <polygraph :stats="stats"></polygraph>
+  </svg>
+  <!-- controls -->
+  <div v-for="stat in stats">
+    <label>{{stat.label}}</label>
+    <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">
+    <button @click="add">Add a Stat</button>
+  </form>
+  <pre id="raw">{{ stats }}</pre>
+</div>
+
+<script>
+const App = {
+  components: {
+    Polygraph
+  },
+  setup() {
+    const newLabel = Vue.ref('')
+    const stats = Vue.reactive([
+      { label: 'A', value: 100 },
+      { label: 'B', value: 100 },
+      { label: 'C', value: 100 },
+      { label: 'D', value: 100 },
+      { label: 'E', value: 100 },
+      { label: 'F', value: 100 }
+    ])
+
+    function add(e) {
+      e.preventDefault()
+      if (!newLabel.value) return
+      stats.push({
+        label: newLabel.value,
+        value: 100
+      })
+      newLabel.value = ''
+    }
+
+    function remove(stat) {
+      if (stats.length > 3) {
+        stats.splice(stats.indexOf(stat), 1)
+      } else {
+        alert('Can\'t delete more!')
+      }
+    }
+
+    return {
+      newLabel,
+      stats,
+      add,
+      remove
+    }
+  }
+}
+
+Vue.createApp().mount(App, '#demo')
+</script>
+
+<style>
+body {
+    font-family: Helvetica Neue, Arial, sans-serif;
+}
+
+polygon {
+    fill: #42b983;
+    opacity: .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;
+}
+</style>
similarity index 99%
rename from packages/vue/examples/todomvc-composition.html
rename to packages/vue/examples/composition/todomvc.html
index eee236e611fdeb36a678d0f7c40426ff342dffc9..0fba33f063dccc12bbb4a46df0c6002fdd4068fc 100644 (file)
@@ -1,4 +1,4 @@
-<script src="../dist/vue.global.js"></script>
+<script src="../../dist/vue.global.js"></script>
 <link rel="stylesheet" href="https://unpkg.com/todomvc-app-css/index.css">
 
 <div id="app">
@@ -44,7 +44,7 @@
         <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-if="state.todos.length > state.remaining">
         Clear completed
       </button>