A presentation at Boston VueJS in July 2019 in Boston, MA, USA by Divya
Don’t Hate the Player Hate the GAME
What’s in Vue3?
Nutrition Facts Serving Size Amount Per Serving Calories 0 Warnings Do not consume While reading Hacker News Consume in moderation
<template> <div> Hello {{ msg }} </div> </template> <script> export default { name: “HelloWorld”, props: { msg: String }, } </script>
<template> <div> Hello {{ msg }} </div> </template> <script> export default { name: “HelloWorld”, props: { msg: String }, setup(props, context) { } } </script>
<template> <div> {{ msg }} </div> </template> <script> import { value } from “vue-function-api”; export default { name: “HelloWorld”, props: { name: String }, data() { return { msg: hello ${this.name}
; } }, }; </script>
<template> <div> {{ msg }} </div> </template> <script> import { value } from “vue-function-api”; export default { name: “HelloWorld”, props: { name: String }, data() { return { msg: hello ${this.name}
; } }, setup(props) { … } }; </script>
<template> <div> {{ msg }} </div> </template> like data
<script> export default { name: “HelloWorld”, props: { name: String }, setup(props) { return { msg: `hello ${props.name}!` } } } </script><template> <div> {{ msg }} </div> </template> only available in render context
<script> export default { name: “HelloWorld”, props: { name: String }, setup(props) { return { msg: `hello ${props.name}!` } } } </script><template> <div> <h2>Hello {{ text }}</h2> <div> <input v-model=”text”> </div> </div> </template>
<template> <div> <h2>Hello {{ text }}</h2> <div> <input v-model=”text”> </div> </div> </template> <script> import { value } from “vue-function-api”; export default { name: “HelloWorld”, setup(props) { const text = value(null) return { text } } } </script>
<template> data <div> <span>count is {{ count }}</span> <br> <span>plus one is {{ plusOne }}</span> <div> <button @click=”increment”>Increment</button> </div> </div> </template> computed method
<script> import { value, computed, watch } from “vue-function-api”; export default { name: “Counter”, setup() { // reactive state const count = value(0); // computed state const plusOne = computed(() => count.value + 1); // method const increment = () => { count.value++; }; // watch watch(l a it on i s o p om C Functions Vue Hooks
function useMouse() { const x = value(0) const y = value(0) const update = e => { x.value = e.pageX y.value = e.pageY } onMounted(() => { window.addEventListener(‘mousemove’, update) }) onUnmounted(() => { window.removeEventListener(‘mousemove’, update) }) return { x, y } } // in consuming component const Component = { setup() { const { x, y } = useMouse() const { z } = useOtherLogic() return { x, y, z } }, template: <div>{{ x }} {{ y }} {{ z }}</div>
}
import { value, computed } from “vue-function-api”; export default function useCounter() { const count = value(0); const increment = () => { count.value = count.value + 1; }; const plusOne = computed(() => count.value + 1); return { count, increment, plusOne }; }
<template> <div> <span>count is {{ count }}</span> <span>{{ plusOne }}</span> <div> <button @click=”increment”>Increment</button> </div> </div> </template> <script> import useCounter from “../functions/useCounter”; export default { name: “Counter”, setup(props, context) { const { count, increment, plusOne } = useCounter(); return { count, increment, plusOne }; } }; </script>
Theoretical API Actual API
npm install vue-function-api —save yarn add vue-function-api
<template> <div id=”map” ref=”map”></div> </template>
<script> const mapboxgl = require(‘mapbox-gl’); var turf = require(‘turf’) export default { name: “RunnerMap”, data() { return { route: null, map: null, raf: null, timestamp: null, loaded: } }, created() { mapboxgl.accessToken = “API_KEY” fetch(“https://gist.githubusercontent.com/shortdiv/XXXX.geojso .then(response => { return response.json(); }) .then(data => { this.route = data }) }, watch:{ loaded() {<template> <div id=”map” ref=”map”></div> </template>
<script> const mapboxgl = require(‘mapbox-gl’); var turf = require(‘turf’) export default { name: “RunnerMap”, data() { return { route: null, map: null, raf: null, timestamp: null, loaded: } }, created() { mapboxgl.accessToken = “API_KEY” fetch(“https://gist.githubusercontent.com/shortdiv/XXXX.geojso .then(response => { return response.json(); }) .then(data => { this.route = data }) }, watch:{ loaded() {mounted() { var map = new mapboxgl.Map({ container: this.$refs.map, // container id style: ‘mapbox://styles/mapbox/dark-v10’, //hosted style id center: [-71.46933442476096,42.25342191415163], // starting zoom: 12 // starting zoom }); this.map = map map.on(‘load’, () => { this.loaded = true map.addSource(‘point’, { “type”: “geojson”, “data”: { “type”: “Feature”, “properties”:{}, “geometry”: { “type”: “Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10,
mounted() { var map = new mapboxgl.Map({ container: this.$refs.map, // container id style: ‘mapbox://styles/mapbox/dark-v10’, //hosted style id center: [-71.46933442476096,42.25342191415163], // starting zoom: 12 // starting zoom }); this.map = map map.on(‘load’, () => { this.loaded = true map.addSource(‘point’, { “type”: “geojson”, “data”: { “type”: “Feature”, “properties”:{}, “geometry”: { “type”: “Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10,
this.map = map map.on(‘load’, () => { this.loaded = true map.addSource(‘point’, { “type”: “geojson”, “data”: { “type”: “Feature”, “properties”:{}, “geometry”: { “type”: “Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10, “circle-color”: “#007cbf” } }); }) } } </script>
}) }, watch:{ loaded() { this.timestamp = performance.now() this.raf = requestAnimationFrame(animateMarker.bind(this)) function animateMarker() { let time = performance.now() //ms const duration = 6 * 1000 let speed = 5000 / duration //in m const path = turf.lineString(this.route.geometry.coordinat const timeElapsed = time - this.timestamp if (timeElapsed * speed >= 5000) { cancelAnimationFrame(this.raf) } else { var distTravelled = (timeElapsed * speed) var waypoint = turf.along(path, distTravelled, ‘meters’) this.map.getSource(‘point’).setData(waypoint) this.raf = requestAnimationFrame(animateMarker.bind(this)) } } } }, mounted() { var map = new mapboxgl.Map({
<template> <div class=”map—wrapper”> <div id=”map” ref=”map”></div> </div> </template> <script> import { watch, value, onMounted } from “vue-function-api”; const mapboxgl = require(‘mapbox-gl’); import useWaypoint from “../functions/useWaypoint”; export default { props: { data: Object }, setup(props, context) { let { movePoint } = useWaypoint(props.data); const mapInstance = value(null) const lineString = value(null) onCreated(() => { mapboxgl.accessToken = “API_KEY_HERE” fetch(“https://gist.githubusercontent.com/shortdiv/97d74.geojs .then(response => { return response.json();
<template> <div class=”map—wrapper”> <div id=”map” ref=”map”></div> </div> </template> <script> import { watch, value, onMounted } from “vue-function-api”; const mapboxgl = require(‘mapbox-gl’); import useWaypoint from “../functions/useWaypoint”; export default { props: { data: Object }, setup(props, context) { let { movePoint } = useWaypoint(props.data); const mapInstance = value(null) const lineString = value(null) onCreated(() => { mapboxgl.accessToken = “API_KEY_HERE” fetch(“https://gist.githubusercontent.com/shortdiv/97d74.geojs .then(response => { return response.json();
export default { props: { data: Object }, setup(props, context) { let { movePoint } = useWaypoint(props.data); const mapInstance = value(null) const lineString = value(null) onCreated(() => { mapboxgl.accessToken = “API_KEY_HERE” fetch(“https://gist.githubusercontent.com/shortdiv/97d74.geojs .then(response => { return response.json(); }) .then(data => { lineString.value = data }) }) onMounted(() => { var map = new mapboxgl.Map({ container: context.refs.map, style: ‘mapbox://styles/mapbox/dark-v10’, center: [-71.46933442476096,42.25342191415163], zoom: 12 });
}) onMounted(() => { var map = new mapboxgl.Map({ container: context.refs.map, style: ‘mapbox://styles/mapbox/dark-v10’, center: [-71.46933442476096,42.25342191415163], zoom: 12 }); map.on(‘load’, () => { mapInstance.value = map map.addSource(‘point’, { “type”: “geojson”, “data”: { “type”:”Feature”, “properties”:{}, “geometry”:{ “type”:”Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10,
“type”:”Feature”, “properties”:{}, “geometry”:{ “type”:”Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10, “circle-color”: “#007cbf” } }); }); watch(() => lineString.value, val => { moveMap(mapInstance.value) }) } } </script>
import { value, state } from “vue-function-api”; var turf = require(“turf”); export default function useWaypoint(route) { const movePoint = map => { const waypointVal = value({ type: “Feature”, geometry: { type: “Point”, coordinates: route.geometry.coordinates[0] } }); const waypointState = state({ timestamp: performance.now(), raf: null }); const animateMarker = () => { let time = performance.now(); //ms const duration = 6 * 1000; // 6000ms or 6s let speed = 5000 / duration; //in m const path = turf.lineString(route.geometry.coordinates); const timeElapsed = time - waypointState.timestamp; if (timeElapsed * speed >= 5000) { cancelAnimationFrame(waypointState.raf); } else { var distTravelled = timeElapsed * speed;
import { value, state } from “vue-function-api”; var turf = require(“turf”); export default function useWaypoint(route) { const movePoint = map => { const waypointVal = value({ type: “Feature”, geometry: { type: “Point”, coordinates: route.geometry.coordinates[0] } }); const timeStamp = value(performance.now()); const raf = value(null); const animateMarker = () => { let time = performance.now(); //ms const duration = 6 * 1000; // 6000ms or 6s let speed = 5000 / duration; //in m const path = turf.lineString(route.geometry.coordinates); const timeElapsed = time - timestamp.value; if (timeElapsed * speed >= 5000) { cancelAnimationFrame(waypointState.raf); } else { var distTravelled = timeElapsed * speed; waypointVal.value = turf.along(path, distTravelled, “meters”
const timeStamp = value(performance.now()); const raf = value(null); const animateMarker = () => { let time = performance.now(); //ms const duration = 6 * 1000; // 6000ms or 6s let speed = 5000 / duration; //in m const path = turf.lineString(route.geometry.coordinates); const timeElapsed = time - timestamp.value; if (timeElapsed * speed >= 5000) { cancelAnimationFrame(waypointState.raf); } else { var distTravelled = timeElapsed * speed; waypointVal.value = turf.along(path, distTravelled, “meters” map.getSource(‘point’).setData(waypointVal.value) raf.value = requestAnimationFrame( animateMarker.bind(this) ); } }; waypointState.raf = requestAnimationFrame( animateMarker.bind(this) ); } return { movePoint } }
<template> <div class=”map—wrapper”> <div id=”map” ref=”map”></div> </div> </template> <script> import { watch, value, onMounted } from “vue-function-api”; const mapboxgl = require(‘mapbox-gl’); import useWaypoint from “../functions/useWaypoint”; export default { props: { data: Object }, setup(props, context) { let { movePoint } = useWaypoint(props.data); const mapInstance = value(null) const lineString = value(null) onCreated(() => { mapboxgl.accessToken = “API_KEY_HERE” fetch(“https://gist.githubusercontent.com/shortdiv/97d74.geojs .then(response => { return response.json();
<template> <div class=”map—wrapper”> <div id=”map” ref=”map”></div> </div> </template> <script> import { watch, value, onMounted } from “vue-function-api”; const mapboxgl = require(‘mapbox-gl’); import useWaypoint from “../functions/useWaypoint”; export default { props: { data: Object }, setup(props, context) { let { movePoint } = useWaypoint(props.data); const mapInstance = value(null) const lineString = value(null) onCreated(() => { mapboxgl.accessToken = “API_KEY_HERE” fetch(“https://gist.githubusercontent.com/shortdiv/97d74.geojs .then(response => { return response.json();
“type”:”Point”, “coordinates”:[-71.51794373989105,42.23001485466201] } } }); map.addLayer({ “id”: “point”, “source”: “point”, “type”: “circle”, “paint”: { “circle-radius”: 10, “circle-color”: “#007cbf” } }); }); watch(() => lineString.value, val => { moveMap(mapInstance.value) }) } } </script>
Will stuff change in Vue3? Yes, Most Certainly
Vue 3 is coming for you