Quasar (v1)
vueのUIというような位置づけで紹介されているところが多いが、プロジェクト作成時に基本的なフォルダ構成も作成してくれてVueRouterやVuexが使える構造になっており、SPAやSSRを指定してビルドする機能があるのでUIというよりははじめから豊富なコンポーネントを持っているNuxtのような位置づけだと思った。
ロードマップ
ドキュメント
見やすいが、アクセスできなくなってる事が多い気がするのが辛すぎる
Vueコンポーネント
Vueディレクティブ
奇麗で豊富なので楽しい。
個人的に気になったコンポーネントとディレクティブ
- carousel
- drawer
- dialog フルスクリーン
- time
- date
- infinite-scroll
- knob ドラッグで変更できる
- parallax
- popup-edit
- splitter 左右の幅をドラッグ
- stepper
- tab-panels
- timeline
- tree
- virtual-scroll
- mutation redo undo
プロジェクト作成方法
基本的な構造
Path | メモ | リンク |
---|---|---|
quasar.conf.js | ビルド設定等 | quasar-conf-js |
src/index.template.html | html、head、bodyタグが記載された一番外枠のファイル(configのhtmlVariablesで変数を使用したりしている) | |
src/App.vue | ||
src/boot | Vueがインスタンス化される前に実行 | boot-files |
src/store | ここにstoreを記述(Vuex) | vuex-store |
src/router/routes.js | ここにルーティングを記述(VueRouter) | routing |
src/components | 自作コンポーネント等(使わないでpagesのみで作るのでもOK) | |
src/layouts | 画面用コンポーネント(pagesを読み込む用) | |
src/pages | 画面用コンポーネント | |
src/assets | vueファイルからの相対パス./でアクセス可能なもの | App Handling Assets |
src/statics | ビルド時にdistのstaticsにデプロイされる | App Handling Assets |
src/css | プロジェクト作成時に設定した形式(Pick your favorite CSS preprocessor)のcssファイルが入る(SCSSやSASS等) |
プロジェクト作成後の整備(とりあえずこれを設定しておけば使えるようになりそうというもの)
historyモードに変更
quasar.conf.js
vueRouterMode: 'history',
テーマカラーを変更
src/css/quasar.variables.sass
$primary : #027BE3
$secondary : #26A69A
$accent : #9C27B0
$positive : #21BA45
$negative : #C10015
$info : #31CCEC
$warning : #F2C037
FontAwesomeを使えるようにする
quasar.conf.js
// https://github.com/quasarframework/quasar/tree/dev/extras
extras: [
// 'ionicons-v4',
// 'mdi-v4',
- // 'fontawesome-v5',
+ 'fontawesome-v5',
// 'eva-icons',
// 'themify',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
'roboto-font', // optional, you are not bound to it
'material-icons' // optional, you are not bound to it
],
FontAwesomeで使用するアイコンのclassをそのまま設定することで使用可能
<q-icon name="fas fa-question-circle" />
axiosを設定する
src/boot/axios.js
import Vue from 'vue';
import axios from 'axios';
const axiosInstance = axios.create({
baseURL: 'http://example.com',
'Content-Type': 'application/json',
Accept: 'application/json'
});
// *.vueからはthis.$axiosで呼び出せます
Vue.prototype.$axios = axiosInstance;
export { axiosInstance };
quasar.conf.js
boot: [
'axios'
],
VueRouterにナビゲーションガードを設定してログイン判定等を行う
src/boot/auth.js
import { axiosInstance } from 'boot/axios';
export default ({ router, store, Vue }) => {
router.beforeEach((to, from, next) => {
to.matched.some(async (record) => {
// https://router.vuejs.org/ja/guide/advanced/meta.html
if (!record.meta.requiresAuth) {
// ログイン不要
next();
} else {
// ログイン必要
let postData = new FormData();
postData.append('name', 'value');
await axiosInstance.post('endpoint', postData)
.then(response => {
next();
})
.catch(error => {
if (error.response.status === 401) {
next({ name: 'login' });
} else {
next({ name: 'home' });
}
})
.finally(() => {
// finally
});
}
});
});
};
quasar.conf.js
boot: [
'axios',
'auth'
],
lodash等のツールを使えるようにする
src/boot/lodash.js
import _ from 'lodash';
export default ({ app, router, Vue }) => {
window._ = _;
};
quasar.conf.js
boot: [
'axios',
'auth',
'lodash'
],
mixinを使う
src/mixins/api.js
import { axiosInstance } from 'boot/axios';
export default {
methods: {
post: (url, data) => {
// return Promise
return axiosInstance.post(url, data);
}
}
};
src/pages/XXXXXX.vue
<template>
<q-page class="flex flex-center">
<img @click="callMixin" alt="Quasar logo" src="~assets/quasar-logo-full.svg">
</q-page>
</template>
<script>
import Api from '../mixins/api';
export default {
name: 'XXXXXX',
mixins: [Api],
methods: {
async callMixin () {
let response = await this.post('endpoint', {});
}
}
};
</script>
Vuexを使う
exampleストアのモジュールを作る
src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import example from './example';
Vue.use(Vuex);
/*
* If not building with SSR mode, you can
* directly export the Store instantiation
*/
// *.vueからはthis.$storeで呼び出せます
// how to access state: this.$store.state.example.XXXXXX
// how to access getter: this.$store.getters.example.someGetter
// how to call mutation: this.$store.commit('example/someMutation', val)
// how to call action: this.$store.dispatch('example/someAction', val)
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
modules: {
example
},
// enable strict mode (adds overhead!)
// for dev mode only
strict: process.env.DEV
});
return Store;
}
src/store/example/index.js
import state from './state';
import * as getters from './getters';
import * as mutations from './mutations';
import * as actions from './actions';
export default {
namespaced: true,
getters,
mutations,
actions,
state
};
Actions
src/store/example/actions.js
// action
// trriger: store.dispatch('someAction')
// action method is Includes asynchronous processing
export function someAction (context) {
// context.commit('someMutation'); // call mutation
// context.dispatch('someAction'); // call action
// context.state.XXXXXX; // access store.state
// context.getters.someGetter; // access store.getter
}
Getters
src/store/example/getters.js
// getter
// trriger: store.getters.someGetter
// Accessible as Computed Properties
export function someGetter (state) {
// return state.XXXXXX + state.XXXXXX;
}
Mutations
src/store/example/mutations.js
// mutation
// trriger store.commit('methodName')
// Mutation methods must be synchronous
export function someMutation (state) {
// state.example = 'example';
}
State
src/store/example/state.js
export default {
example: ''
};