chore: add a few 2.x examples
This commit is contained in:
		
							parent
							
								
									24f6d63c6a
								
							
						
					
					
						commit
						e0a9cf5ace
					
				
							
								
								
									
										78
									
								
								packages/vue/examples/classic/commits.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								packages/vue/examples/classic/commits.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										169
									
								
								packages/vue/examples/classic/grid.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								packages/vue/examples/classic/grid.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										177
									
								
								packages/vue/examples/classic/svg.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								packages/vue/examples/classic/svg.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
| @ -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"> | ||||
							
								
								
									
										74
									
								
								packages/vue/examples/composition/commits.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								packages/vue/examples/composition/commits.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										175
									
								
								packages/vue/examples/composition/grid.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								packages/vue/examples/composition/grid.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										170
									
								
								packages/vue/examples/composition/svg.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								packages/vue/examples/composition/svg.html
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
| @ -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> | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user