Vue CDN Playground
by Keith Rowles • 27/10/2023Vue
Summary
Playing around with the Vue JS library using CDN links. 3 examples - product page, data binding and dynamic pages.
I will demonstrate some of these Vue JS features:
- v-bind
- v-for
- v-if
- v-else
- v-text
- v-html
- v-show
- v-on
- v-model
- v-slot
CDN Link
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
I will also add the bootstrap css framework for some basic styles.
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD"
crossorigin="anonymous"
/>
<!-- Bootstrap Icons -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css"
/>
Demo 1
Product page example using v-bind and v-for. Using Vue JS options API.
<div class="container-sm">
<div id="app">
<h1>{{ name }}</h1>
<img v-bind:src="imgSrc" v-bind:alt="name" class="img-fluid" />
<p>{{description}}</p>
<div>{{price}}</div>
<section class="container">
<div
v-for="product in products"
v-bind:key="product.id"
id="display-list"
class="row d-flex mb-3 align-items-center"
>
<div class="col-sm-4">
<img
class="img-fluid d-block"
v-bind:src="product.image"
v-bind:alt="product.name"
/>
</div>
<div class="col">
<h3 class="text-info">{{product.name}}</h3>
<p class="mb-0">{{product.description}}</p>
<div class="h5 float-right">{{product.price}}</div>
</div>
</div>
</section>
</div>
</div>
// Global API Initialization
Vue.createApp({
data() {
return {
name: 'Bamboo Thermal Ski Coat',
description:
'Youll be the most environmentally conscious skier on the slopes - and the most stylish - wearing our fitted bamboo thermal ski coat, made from organic bamboo with recycled plastic down filling.',
imgSrc:
'https://hplussport.com/wp-content/uploads/2016/12/ski-coat_LYNDA_29940.jpg',
price: 99,
products: [
{
id: '532',
name: 'Slicker Jacket',
description:
'Wind and rain are no match for our organic bamboo slicker jacket for men and women. Triple stitched seams, zippered pockets, and a stay-tight hood are just a few features of our best-selling jacket.',
price: '125',
image_title: 'slicker-jacket_lynda_29941',
image:
'https://hplussport.com/wp-content/uploads/2016/12/slicker-jacket_LYNDA_29941.jpg',
},
{
id: '530',
name: 'Bamboo Thermal Ski Coat',
description:
"You'll be the most environmentally conscious skier on the slopes - and the most stylish - wearing our fitted bamboo thermal ski coat, made from organic bamboo with recycled plastic down filling.",
price: '99',
image:
'https://hplussport.com/wp-content/uploads/2016/12/ski-coat_LYNDA_29940.jpg',
},
{
id: '516',
name: 'Unisex Thermal Vest',
description:
"Our thermal vest, made from organic bamboo with recycled plastic down filling, is a favorite of both men and women. You'll help the environment, and have a wear-easy piece for many occasions.",
price: '95',
image:
'https://hplussport.com/wp-content/uploads/2016/12/unisex-thermal-vest_LYNDA_29944.jpg',
},
],
};
},
}).mount('#app');
Open demo on Code Pen.
Link to DemoDemo 2
This is a sandbox and playground showing Vue JS options API.
const { createApp } = Vue;
const app = createApp({
data() {
return {
count: 0,
message: 'Hello Vue!',
rawHtml:
'<span style="color: red">This should be red. Output the html.</span>',
imageSrc: 'http://127.0.0.1:5500/business-blocks.jpg',
isPale: true,
isButtonDisabled: true,
alert: {
role: 'alert',
class: 'alert alert-primary',
},
number: 10,
ok: true,
seen: true,
url: 'https://vuejs.org',
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - Mystery Guide',
],
},
firstName: 'Keith',
lastName: 'Rowles',
isActive: true,
hasError: true,
error: null,
activeLinkClass: 'link-primary',
bigLinkClass: 'fs-3',
errorClass: 'alert-danger',
activeColour: 'blue',
fontOne: 30,
styleObject: {
color: 'green',
fontSize: '20px',
},
styleObjectOverride: {
fontWeight: 'bold',
fontStyle: 'italic',
},
isVueAwesome: false,
sometype: 'B',
items: [
{ message: 'Foo', id: 1 },
{ message: 'Bar', id: 2 },
],
myObject: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10',
},
numbers: [1, 2, 3, 4, 5],
name: 'Vue JS',
newmessage: 'This is a new message',
picked: 'One',
selected: 'A',
names: ['Tom', 'Bob', 'Sam'],
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' },
],
show: true,
};
},
provide() {
return {
footertitle: 'My fav footer title',
};
},
methods: {
showMe() {
this.seen = !this.seen;
},
increment() {
this.count++;
},
onSubmit() {
console.log('Prevent Default');
},
greet(event) {
alert(`Hello ${this.name}`);
if (event) {
alert(event.target.tagName);
}
},
say(message) {
alert(message);
},
warn(message, event) {
if (event) {
event.preventDefault();
}
alert(message);
},
},
// Lifecycle Hooks
mounted() {
this.increment(), console.log(this.$refs.names);
},
onMounted() {},
onUnmounted() {},
// Computed Property - Are Cached - Must Return Something
computed: {
publishedBooksMessage() {
return this.author.books.length > 0 ? 'Yes' : 'No';
},
fullName: {
get() {
return this.firstName + ' ' + this.lastName;
},
set(newValue) {
[this.firstName, this.lastName] = newValue.split(' ');
},
},
classObject() {
return {
active: this.isActive && !this.error,
'text-dark': !this.error,
'text-uppercase': !this.error,
};
},
evenNumbers() {
return this.numbers.filter((n) => n % 2 === 0);
},
},
});
app.component('myheading', {
props: ['headingtext'],
template: `
<h6>{{headingtext}} <span class="badge bg-secondary">New</span></h6>
`,
});
app.component('blogpost', {
props: ['title'],
template: `
<h4>{{ title }}</h4>
`,
});
app.component('newspost', {
props: {
newsTitle: String,
newsDate: Number,
},
template: `
<h4>{{ newsTitle }}</h4>
<p>{{ newsDate }}</p>
<button @click="$emit('customEvent')" class="btn btn-primary">click me</button>
`,
emits: ['customEvent'],
});
app.component('appFooter', {
inject: ['footertitle'],
template: `
<h2>This is the footer - {{ footertitle }}</h2>
`,
});
app.mount('#app');
Some styles.
.pale {
color: palevioletred;
}
.boldtext {
font-weight: bold;
}
.italictext {
font-style: italic;
}
.active {
background-color: brown;
padding: 20px;
color: white;
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.fade-enter-active {
transition: all 0.5s ease-out;
}
.fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.fade-enter-from,
.fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
.imgSrc {
width: 50%;
}
Demo
Open demo on JS Fiddle.
Link to Demo