App development with quasar (pdf)
- 1. Dept. of Smart Finance, Korea Polytechnics Seoul Kangseo Campus
ApplicationDevelopmentw/
QuasarFramework
Basic Course
- 2. QuasarCLIInstallation
• Prerequisite
Node >=12.22.1 and NPM >=6.14.12
• recommendation node version : v14.17.5
check your node and npm : node -v
npm -v
• npm install -g @quasar/cli
Do not use uneven versions of Node i.e. 13, 15, etc. These versions are not tested with Quasar and often cause issues due to their experimental nature. We highly recommend always using the LTS version of Node.
Ref : https://quasar.dev/quasar-cli/installation
- 3. HelloworldⅠ(1/2)
• we create a project folder with Quasar CLI
• quasar create <folder_name>
Ref : https://quasar.dev/quasar-cli/installation
(base) waynehwang@wayneui-MacBookPro temp % quasar create hello
___
/ _ _ _ __ _ ___ __ _ _ __
| | | | | | |/ _` / __|/ _` | '__|
| |_| | |_| | (_| __ (_| | |
_____,_|__,_|___/__,_|_|
? Project name (internal usage for dev) hello
? Project product name (must start with letter if building mobile apps) hello
? Project description hello world
? Author wayne hwang <wonyong@wonyong.net>
? Pick your CSS preprocessor: SCSS
? Check the features needed for your project: ESLint (recommended), Vuex, Axios
? Pick an ESLint preset: Prettier
? Continue to install project dependencies after the project has been created? (
recommended) NPM
Quasar CLI · Generated "hello".
[*] Installing project dependencies …
[*] Quasar Project initialization finished!
To get started:
cd hello
quasar dev
- 4. Helloworld Ⅰ(2/2)
• Look into package.json, App.vue, routes.js, Index.vue, EssentialLink.vue, …
• Run your app with below command:
quasar dev
- 5. HelloWorldⅡ
• Repository address :
https://github.com/wonyongHwang/kopoPro
fi
le
• git clone https://github.com/wonyongHwang/kopoPro
fi
le
• npm install
• quasar dev
kopoProfile
- 6. HelloWorldⅡ
• In this practice, we don’t have a
drawer and a footer either. So, only
<q-header> is being a
ff
ected by
<q-layout>.
•
layout
<q-layout view="lHh lpr lFf">
reference : https://quasar.dev/layout/layout#understanding-the-view-prop
- 7. HelloWorldⅡ
• quasar can detect platform : $q.platfrom.is.~~
eg> if you will deploy app to mobile device(android,
ios) app can detect platform using $q.platform.is.
cordova
$q.platform
<div v-bind:class="{'main': $q.platform.is.desktop, 'mobile_main': $q.platform.is.ipad || $q.platform.is.mobile}"
class="full-height" style="background-color:rgba(0, 0, 0, 0.7);">
reference : https://quasar.dev/options/platform-detection#introduction
- 11. HelloWorldⅡ
• Get/set scroll position (Quasar Scrolling Utils)
https://quasar.dev/quasar-utils/scrolling-utils#get-set-scroll-position
<script></script>
import {scroll} from 'quasar'
const {getScrollTarget, setScrollPosition} = scroll
export default {
name: 'PageIndex',
data() {
return {
name: "",
email: "",
message: "",
selected_tab: 'about_me',
}
},
methods: {
scrollToElement(id) {
let el = document.getElementById(id)
const target = getScrollTarget(el)
const o
ff
set = el.o
ff
setTop - 65
const duration = 800
setScrollPosition(target, o
ff
set, duration)
}
},
mounted () {
}
}
- 14. homework
• check url
• if you have a own domain, netlify allow you to access your web site
• ‘https(let’s encrypt)’ supports both custom domain and netlify domain
- 18. SignIn
• what you need to implement a sign-in page:
2 Input Text
fi
eld
1 Check Box
1 Button
and more …
- 21. pagelink
• vue syntax for page link :
<router-link to=“/address”> ~~ </router-link>
<router-link to="/signup" >
<center>New User? Click Here to Register.</center>
</router-link>
- 22. Homework
• Place and Organize Input Text
fi
elds (E-mail, Password, etc …)
: center alignment
• Password should be masked while typing
• Place Sign-In / Sign-Up buttons
complete your sign-in / sign-up pages!
- 23. f
irebase
• https://
fi
rebase.google.com/?hl=ko
create a project
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const
fi
rebaseCon
fi
g = {
apiKey: "AIzaSyA~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
authDomain: "kopologinchecker.
fi
rebaseapp.com",
projectId: "kopologinchecker",
storageBucket: "kopologinchecker.appspot.com",
messagingSenderId: "17~~~~~~~~~~~~",
appId: "1:17~~~~~~~~:web:d4~~~~~~~~",
measurementId: “G-H0~~~~~~~~~~~~"
};
- 24. • npm install --save
fi
rebase
• quasar new boot
fi
rebase
->
fi
rebase.js will be generated in src/boot
-> paste
fi
rebase con
fi
guration to
fi
rebase.js
f
irebase
setting config.
ref : https://quasar.dev/quasar-cli/boot-
fi
les
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/analytics'
const firebaseConfig = {
apiKey: "~",
authDomain: "kopologinchecker.firebaseapp.com",
projectId: "kopologinchecker",
storageBucket: "kopologinchecker.appspot.com",
messagingSenderId: “~",
appId: "~",
measurementId: "~"
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
firebase.analytics();
export const auth = firebase.auth();
- 27. • let’s use quasar notify to show success/fail message
https://quasar.dev/quasar-plugins/notify#introduction
f
irebase
sign-in method
auth.signInWithEmailAndPassword(this.text, this.password).then(
(userCredential) => {
console.log(userCredential.user);
this.$router.push({ path: 'home' })
}
).catch(
(err) => {
console.log(err.code);
console.log(err.message);
this.$q.notify({
message: err.message,
color: 'purple'
})
}
)
message, color, postion, textColor, icon, …
import { useQuasar } from 'quasar'
const $q = useQuasar()
$q.notify({
message : "login success",
color : "blue"
})
vue 3
- 28. homework
• implement a sign-up function using
fi
rebase api
• validation logic should be implemented
ex> email/password should not be empty
password should be equal to ‘repeat password’
password must be at least 6 characters long
hint> https://levelup.gitconnected.com/
fi
rebase-auth-management-in-vue-js-with-vuex-9c4a5d9cedc
• move page after sign-up
hint> this.$router.push({ path: 'home' })
import { useRouter, useRoute } from 'vue-router'
export default
{
setup()
{
const router = useRouter()
const route = useRoute()
// Now you can access params like
:
console.log(route.params.id)
;
route.push({path: ‘home’}
)
}
};
vue v3
https://next.router.vuejs.org/guide/advanced/composition-api.html#accessing-the-router-and-current-route-inside-setup
- 30. management
f
irebaseauthw/vuex
• state management pattern and its library
• state : data
• mutations : change state (sync)
• actions : commit mutation (async)
what vuex is
Actions
State
View
Mutations
this.$store.commit
emit, props
Unidirectional
fl
ow
- 31. management
f
irebaseauthw/vuex
• state =
fi
re auth info
• ‘
fi
re auth info’ can acquire when we call
signInWithEmailAndPassword()
createUserWithEmailAndPassword()
and so on.
state
Actions
State
View
Mutations
this.$store.commit
import {auth} from "src/boot/firebase"
export default store(function (/* { ssrContext } */) {
const Store = createStore({
modules: {
// example
},
state: {
fireUser:null
},
…
State
- 32. management
f
irebaseauthw/vuex
• get the current sign-in user is by setting an observer on the Auth object
https://
fi
rebase.google.com/docs/auth/web/manage-users
• state should be null when user signed out
https://
fi
rebase.google.com/docs/auth/web/password-auth?hl=ko
action
actions: {
signOutAction({commit}) {
auth.signOut()
.then(() => {
commit("setFireUser", null);
})
},
authAction({ commit }) {
auth.onAuthStateChanged(user => {
if (user) {
commit("setFireUser", user);
}
});
},
},
mutations: {
setFireUser(state, firebaseUser){
state.fireUser = firebaseUser
}
Actions
Mutations
- 33. management
f
irebaseauthw/vuex
• prepare helper functions
https://joshua1988.github.io/web-development/vuejs/vuex-getters-mutations/
getters
getters: {
getFireUser(state) {
return state.fireUser;
},
isUserAuth(state) {
return !!state.fireUser;
}
},
- 34. management
f
irebaseauthw/vuex
source code
import { store } from 'quasar/wrappers'
import { createStore } from 'vuex'
import {auth} from "src/boot/firebase"
export default store(function (/* { ssrContext } */) {
const Store = createStore({
state: {
fireUser:null
},
actions: {
signOutAction({commit}) {
auth.signOut()
.then(() => {
commit("setFireUser", null);
})
.catch(error => {
commit("setFireError", error.message);
});
},
authAction({ commit }) {
auth.onAuthStateChanged(user => {
if (user) {
commit("setFireUser", user);
} else {
commit("setFireUser", null);
}
});
},
},
getters: {
getFireUser(state) {
return state.fireUser;
},
isUserAuth(state) {
return !!state.fireUser;
}
},
mutations: {
setFireUser(state, firebaseUser){
state.fireUser = firebaseUser
}
},
})
return Store
})
- 35. management
f
irebaseauthw/vuex
• commit state when my application obtain a
fi
rebase auth
• get a
fi
rebase auth to display user info
• check a
fi
rebase auth
usage example
auth.signInWithEmailAndPassword(this.text, this.password).then(
(userCredential) => {
this.$store.commit("setFireUser", userCredential.user);
}
)
<div class="text-h6" align="center">
Hi, {{ this.name }}({{ getFireUser.email }})
<br>
…
computed: {
...mapGetters(["getFireUser", "isUserAuth"])
},
mounted() {
this.authAction();
…
methods: {
...mapActions(["signOutAction","authAction"]),
import { useStore } from "vuex"
;
export default
{
setup()
{
const store = useStore()
;
store.commit("setFireUser", userCredential.user)
;
}
};
vue v3
https://kyounghwan01.github.io/blog/Vue/vue3/composition-api-vuex/#vuex-%E1%84%89%E1%85%A6%E1%84%90%E1%85%B5%E1%86%BC-%E1%84%86%E1%85%B5%E1%86%BE-store-module-1%E1%84%80%E1%85%A2%E1%84%85%E1%85%A9-%E1%84%89%E1%85%B5%E1%86%AF%E1%84%92%E1%85%A2%E1%86%BC
- 36. homework
• When a user logged in, move Vue Page and display user’s email using vuex
• tip>
<div v-if=“getFireUser">~~</div>
computed: {
...mapGetters(["getFireUser", "isUserAuth"])
},
<div class="text-h6" align="center">
Hi,({{ getFireUser.email }})
</div>
import { mapGetters } from "vuex";
- 40. Firestore
• Firestore data add: set() or add()
https://
fi
rebase.google.com/docs/
fi
restore/manage-data/add-data?hl=ko
API
db.collection("users").add({
id: this.text,
name: this.name
})
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
this.$q.notify({
message: "Register Success",
color: 'blue'
})
})
.catch((error) => {
console.error("Error adding document: ", error);
this.$q.notify({
message: error,
color: 'red'
})
});
- 43. Firestore
Data read
db.collection("users").where("id", "==", this.getFireUser.email )
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
this.name = doc.data().name
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
- 44. Homework
• When a user logged in, move page(/home) and display user’s name using vuex
- user name was saved at Firestore, so we have to read the data
fi
rst to show it.
• user name should be displayed on page(/home) even after refreshing page.
- 45. Homework
Hint
<template>
<div>
HOME
<div class="text-h6" align="center">
<div v-if="getFireUser">
Hi,({{ getFireUser.email }})
:) {{ name }}
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue';
import { auth, db } from "src/boot/firebase"
import { useQuasar } from 'quasar'
import { mapGetters, mapActions } from "vuex"; //
export default defineComponent({
name: 'PageIndex',
computed: {
...mapGetters(["getFireUser", "isUserAuth"])
},
updated() {
if(this.getFireUser != null && this.name == ''){ // for refresh page //
db.collection("users").where("id", "==", this.getFireUser.email )
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
this.name = doc.data().name
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}
},
mounted(){ //
this.authAction() // for refresh page //
if(this.getFireUser != null){
db.collection("users").where("id", "==", this.getFireUser.email )
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
this.name = doc.data().name
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}
},
data(){
return{
name : ''
}
},
methods: {
...mapActions(["signOutAction","authAction"])
}
})
</script>
- 47. Implementationof“rememberme”usinglocalStorage
• UI
<q-checkbox v-model="remember" label="Remember Me" color="teal"/>
• Declaration
let remember = ref(‘false')
• mounted()
• When a user tries to log in: if (remember.value == true) {
localStorage.username = email.value;
localStorage.checkbox = remember.value;
} else {
localStorage.username = "";
localStorage.checkbox = "";
}
mounted(){
if(localStorage.checkbox && localStorage.checkbox !==""){
this.remember = true
this.email = localStorage.username
} else {
this.remember = false
}
}
- 61. Menu
• components hierarchy
⎯ MainLayout.vue
EssentialLink.vue
props and emit
icon title
label
link
+
<template>
<q-item clickable tag="a" target="_blank" :href="link">
<q-item-section v-if="icon" avatar>
<q-icon :name="icon" />
</q-item-section>
<q-item-section>
<q-item-label>{{ title }}</q-item-label>
<q-item-label caption> {{ caption }} </q-item-label>
</q-item-section>
</q-item>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'EssentialLink',
props: {
title: {
type: String,
required: true
},
caption: {
type: String,
default: ''
},
link: {
type: String,
default: '#'
},
icon: {
type: String,
default: ''
}
}
})
</script>
props : hey, parent component! control me
- 62. Menu
• components hierarchy
⎯ MainLayout.vue
EssentialLink.vue
props and emit
<EssentialLink v-for="link in essentialLinks" :key="link.title" v-bind="link" />
…
import EssentialLink from 'components/EssentialLink.vue'
const linksList = [
{
title: 'Docs',
caption: 'quasar.dev',
icon: 'school',
link: 'https://quasar.dev'
},
…
export default defineComponent({
name: 'MainLayout',
components: {
EssentialLink
},
setup () {
return {
essentialLinks: linksList,
}
}
…
parent component(MainLayout) now can set child props
- 63. Menu
• <Practice>
- open internal links in a current window
- open external links in a new tab (or window)
props and emit
- 64. Menu
• <Practice> child component(EssentialLink) modi
fi
cation
props
template
props and emit
external: {
type: Boolean,
default: false
}
<template>
<!-- <router-link :to="link" style="text-decoration: none"> -->
<section v-if="external">
<q-item clickable tag="a" target="_target" :href="link">
…
</q-item>
</section>
<section v-else>
<router-link :to="link" style="text-decoration: none; color: inherit;”>
…
</router-link>
</section>
</template>
- 65. Menu
• <Practice> parent component(MainLayout) modi
fi
cation
props and emit
const linksList = [
{
title: 'Home',
caption: 'Home',
icon: 'home',
link: '/home'
},
{
title: 'QR Scanner',
caption: 'QR Check for Admin',
icon: 'qr_code_scanner',
link: 'https://kopologinchecker.web.app/#/qrscanner',
external: true
},
…
- 67. Menu
• <Practice> child component(EssentialLink)
modi
fi
cation
template
methods
props and emit
<q-item clickable tag="a" target="_target" :href="link" @click="sendEvent()">
methods: {
sendEvent() {
this.$emit('closeDrawer');
console.log("emit emit")
}
},
• <Practice> parent component(MainLayout)
modi
fi
cation
template
methods
<EssentialLink v-on:closeDrawer="closeme()"
v-for="link in essentialLinks" :key="link.title" v-bind="link" />
methods: {
closeme() {
console.log('event received');
this.leftDrawerOpen = false;
}
},
- 69. Homework
• save user login timestamps to
fi
restore
• display user login info (w/ timestamp)
build your own table
- 70. q-table
• save user data to Firestore
var cdate = Date.now()
// firestore insert => then we can get doc id to generate qr code
db.collection("qrgen").add({
date: cdate,
id: this.getFireUser.email,
status: this.sliderValue //this.group
})
.then((docRef) => {
// console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
- 71. q-table
• basic layout
<section v-if="!onloading">
<q-table :title="date" :rows="rows" :columns="columns" row-key="no" v-model:pagination="pagination" :filter="filter">
</q-table>
</section>
‘onloading’ set to be false when data is completely loaded data() {
return {
pagination: {
sortBy: 'time',
descending: false,
rowsPerPage: 15, // current rows per page being displayed
},
date: '2019/02/01',
filter : '',
columns : [
{
name: 'no',
required: true,
label: 'SID',
align: 'left',
field: row => row.no,
format: val => `${val}`,
sortable: true
},
{ name: 'name', align: 'left', label: 'Name', field: 'name', sortable: true },
{ name: 'time', align: 'left', label: 'Check-In Time', field: 'time', sortable: true },
{ name: 'temperature', label: 'Temperature', field: 'temperature', sortable: true }
],
rows : [ ],
cnt : 1,
onloading : true
}
},
- 72. q-table
data load
dataLoad: function () {
this.cnt = 1
var now = new Date();
var startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
var timestamp = startOfDay / 1;
db.collection("checkin").where("time", ">=", timestamp) // 오늘 체크인만 확인
.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
var tempRow = {name: '', time:'', temperature:''}
tempRow.name = change.doc.data().name
const getTime = (timeStamp, offset) => {
let d = new Date((timeStamp + offset));
var hour = d.getHours()
var min = d.getMinutes()
var sec = d.getSeconds()
if (hour < 10) { hour = "0" + hour; }
if (min < 10) { min = "0" + min; }
if (sec < 10) { sec = "0" + sec; }
let ret = (d.getMonth()+1)+ "/"+(d.getDate())+ " "+hour+ ":"+min+":"+sec
return ret
}
tempRow.time = getTime(change.doc.data().time,0)
tempRow.no = this.cnt
this.cnt++
tempRow.temperature = change.doc.data().temperature
this.rows.push(tempRow)
}
});
});
this.onloading = false
} // end of dataLoad
ref : https://
fi
rebase.google.com/docs/
fi
restore/query-data/listen?hl=ko
- 73. q-table
• additional function - search
<section v-if="!onloading">
<q-table :title="date" :rows="rows" :columns="columns" row-key="no" :pagination.sync="pagination" :filter="filter">
<template v-slot:top-right>
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search">
<template v-slot:append>
<q-icon name="search"></q-icon>
</template>
</q-input>
</template>
</q-table>
</section>
- 74. q-table
• additional function - date picker
<template v-slot:top-left>
<div class="q-pa-md" style="width: 150px; margin-top: 20px">
<q-input borderless dense debounce="300" v-model="date" mask="date" :rules="['date']">
<template v-slot:append>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
<q-date v-model="date">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat @click="datePicked()"></q-btn>
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
</div>
</template>
should be coded between <q-table> and </q-table>
- 75. q-table
• additional function
- date picker
datePicked(){
this.cnt = 1
this.rows = []
var yyyyMMdd = String(this.date);
var sYear = yyyyMMdd.substring(0,4);
var sMonth = yyyyMMdd.substring(5,7);
var sDate = yyyyMMdd.substring(8,10);
var startOfDay = new Date(Number(sYear), Number(sMonth)-1, Number(sDate));
var timestamp = startOfDay / 1;
var timestampp1d = timestamp + 86400000
db.collection("users").where("date", ">=", timestamp).where("date", "<", timestampp1d)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
var tempRow = {name: '', time:'', temperature:''}
tempRow.name = doc.data().email
const getTime = (timeStamp, offset) => {
let d = new Date((timeStamp + offset));
console.log(d)
var hour = d.getHours()
var min = d.getMinutes()
var sec = d.getSeconds()
if (hour < 10) { hour = "0" + hour; }
if (min < 10) { min = "0" + min; }
if (sec < 10) { sec = "0" + sec; }
let ret = (d.getMonth()+1)+ "/"+(d.getDate())+" "+hour+ ":"+min+":"+sec
return ret
}
tempRow.time = getTime(doc.data().date,0)
tempRow.no = this.cnt
this.cnt++
tempRow.name = doc.data().name
this.rows.push(tempRow)
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}
- 76. q-table
• additional function - csv export
<div align="right">
<q-btn
color="primary"
icon-right="archive"
label="Export to csv"
no-caps
@click="exportTable"
>
</q-btn>
</div>
exportTable () {
var columns = this.columns
var rows = this.rows
// naive encoding to csv format
const content = [columns.map(col => this.wrapCsvValue(col.label))].concat(
rows.map(row => columns.map(col => this.wrapCsvValue(
typeof col.field === 'function'
? col.field(row)
: row[ col.field === void 0 ? col.name : col.field ],
col.format
)).join(','))
).join('rn')
const status = exportFile(
'table-export.csv',
content,
'text/csv'
)
if (status !== true) {
$q.notify({
message: 'Browser denied file download...',
color: 'negative',
icon: 'warning'
})
}
},
- 77. q-table
• additional function - csv export
wrapCsvValue (val, formatFn) {
let formatted = formatFn !== void 0
? formatFn(val)
: val
formatted = formatted === void 0 || formatted === null
? ''
: String(formatted)
formatted = formatted.split('"').join('""')
/**
* Excel accepts n and r in strings, but some other CSV parsers do not
* Uncomment the next two lines to escape new lines
*/
// .split('n').join('n')
// .split('r').join('r')
return `"${formatted}"`
},
import { exportFile } from 'quasar'
- 82. cordova
• npm install -g cordova
• quasar dev -m android --ide
android studio error might be occurred :
“Installed Build Tools revision 31.0.0 is corrupted. Remove and install again using the SDK Manager.”
if you get above error, then you should modify version settings in your build.grade as below image
then type below command on your terminal (https://stackover
fl
ow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted)
cd ~/Library/Android/sdk/build-tools/31.0.0 && mv d8 dx && cd lib && mv d8.jar dx.jar
then close android studio and re-run “quasar dev -m android —ide"
- 84. cordova
• quasar build -m cordova -T android
• brew install gradle
if you get a net error on simulator, then check you port in quasar.conf.js
- 86. cordova
• quasar dev -m cordova -T ios
• quasar build -m cordova -T ios
• https://www.youtube.com/watch?v=P_Ox5s4anCI
ios
- 88. BasicStructure
• setup is called between “before created” and “created”
• you can set a style whatever you want
step 1
<template>
<div class="test">
Hello World, {{ name }}
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'PageIndex',
setup() {
const name = "KOPO"
return {
name
}
}
})
</script>
<style lang="scss">
.test {
color: red;
background-color: yellow;
text-align: center;
font-size: 30px;
}
</style>
- 89. BasicStructure
• add function “printName”
add a function
<template>
<div class="test">
Hello World, {{ name }}
<p></p>
{{ printName() }}
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'PageIndex',
setup() {
const name = "KOPO"
const printName = () => {
return name + "!!"
}
return {
name,
printName
}
}
})
</script>
- 90. BasicStructure
• add a parameter : param
• call the function with parameter
add a parameter
<template>
<div class="test">
Hello World, {{ name }}
<p></p>
{{ printName(name) }}
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'PageIndex',
setup() {
const name = "KOPO"
const printName = (param) => {
return 'hello '+ param + "!!"
}
return {
name,
printName
}
}
})
</script>
- 91. BasicStructure
• we want to change name string when a button is clicked.
but, the result is …
• tip> button width dynamically can be set.
use $ref !
add a button
<template>
<div class="test" ref="topitem">
Hello World, {{ name }}
<p></p>
{{ printName(name) }}
</div>
<q-btn
@click="changeName"
class="button is-primary"
color="primary"
label="BUTTON"
:style="{width: itemWidth+'px'}" />
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'PageIndex',
mounted() {
this.itemWidth = this.$refs.topitem.clientWidth
console.log(this.itemWidth)
},
setup() {
let name = "KOPO"
let itemWidth = ref(0)
const printName = (param) => {
return 'hello '+ param + "!!"
}
const changeName = () => {
name = "Button Clicked"
console.log("name chaged? ", name)
}
return {
name,
itemWidth,
printName,
changeName
}
}
})
</script>
<style lang="scss">
.test {
color: red;
background-color: yellow;
text-align: center;
font-size: 30px;
width: 300px;
}
</style>
- 92. BasicStructure
• “KOPO” —> ref(“KOPO”)
• name —> name.value
use ref to make the variable to be reactive
setup() {
let name = ref("KOPO")
let itemWidth = ref(0)
const printName = (param) => {
return 'hello '+ param + "!!"
}
const changeName = () => {
name.value = "Button Clicked"
console.log("name chaged? ", name)
}
if you use object or array data, use reactive(“~”) instead ref(“~”)