QPANC - 第 12 部分 - Quasar - 服务
QPANC 是 Quasar PostgreSQL ASP NET Core 的首字母。 来源 简介 第一部分 - ASP.NET - 启动项目 第 2 部分 - PostgreSQL 第 3 部分 - ASP.NET - 注册服务和读取环境变量 第 4 部分 - ASP.NET - 实体框架和 ASP.NET 核心标识 第 5 部分 - ASP.NET - 使用 Swagger 的交互式文档
QPANC 是 Quasar PostgreSQL ASP NET Core 的首字母。
-
来源
-
简介
-
第一部分 - ASP.NET - 启动项目
-
第 2 部分 - PostgreSQL
-
第 3 部分 - ASP.NET - 注册服务和读取环境变量
-
第 4 部分 - ASP.NET - 实体框架和 ASP.NET 核心标识
-
第 5 部分 - ASP.NET - 使用 Swagger 的交互式文档
-
第 6 部分 - ASP.NET - 区域化
-
第 7 部分 - ASP.NET - 身份验证和授权
-
第 8 部分 - ASP.NET - CORS
-
第 9 部分 - Quasar - 项目创建和配置
-
第 10 部分 - Quasar - 设置和自定义
-
第 11 部分 - Quasar - 组件 - SPA 和 SSR 之间的区别
-
第 12 部分 - Quasar - 服务
-
第 13 部分 - Quasar - 区域化和存储
-
第 14 部分 - Quasar - 使用 API
-
第 15 部分 - Quasar - 登录
-
第 16 部分 - 类星体 - 保护区
-
第 17 部分 - 类星体 - 记录
-
第 18 部分 - Docker - Linux 虚拟机
-
第 19 部分 - Docker - 注册表和构建
-
第 20 部分 - Docker - Traefik 和发布
-
在线演示
24 将对象注入到组件、存储和路由中。
为了一个SSR
应用程序的正常运行,需要将一些服务以隔离的方式实例化,使得一个用户无法访问发往另一个用户的实例,简而言之,所有的服务都必须在用户范围内进行隔离。
实现这一目标的第一步是创建一个实用程序,将这些服务注入components
、store
和routes
。
QPANC.App/src/boot/inject.js
import Vue from 'vue'
const mixins = []
const inject = function (bootCb) {
return async function (ctx) {
const { app, router, store } = ctx
let boot
if (typeof bootCb === 'function') {
const response = bootCb(ctx)
boot = response.then ? await response : response
} else {
boot = bootCb
}
for (const name in boot) {
const key = `$${name}`
if (mixins.indexOf(name) === -1) {
mixins.push(name)
Vue.mixin({
beforeCreate () {
const options = this.$options
if (options[name]) {
this[key] = options[name]
} else if (options.parent) {
this[key] = options.parent[key]
}
}
})
}
app[name] = boot[name]
store[key] = boot[name]
router[key] = boot[name]
}
}
}
export default inject
现在,一个使用示例:
假设我们有一个在控制台上打印消息Hello World
的服务:
class DummieService {
sayHello ({ name }) {
console.log(`${name}: Hello Wolrd`)
}
}
现在我们想将上述服务的一个实例注入到所有componentes
、stores
和routes
中,我们可以在引导文件中进行。
import inject from './inject'
import DummieService from 'services/dummie'
export default inject(({ Vue }) => {
const dummie = new DummieService()
return {
dummie: dummie
}
})
完成后,我们可以在componentes
和stores
上访问this.$dummie
,以及在导航守卫上访问router.$dummie
,以下是一些示例:
示例/页面/dummy.js
export default {
data () {
const initialMsg = this.$dummie.sayHello({ name: 'me' })
return {
msg: initialMsg
}
},
methods: {
changeName ({ name }) {
this.msg = this.$dummie.sayHello({ name })
}
}
}
示例/商店/dummie.js
export default {
namespaed: true,
state () {
return {
name: 'me',
msg: ''
}
},
mutations: {
name (state, value) { state.name = value },
msg (state, value) { state.msg = value }
},
actions: {
setMessage ({ commit }, name) {
const msg = this.$dummie.sayHello({ name })
commit('msg', msg)
}
},
getters: {
getMessage (state) {
return this.$dummie.sayHello({ name: state.name })
}
}
}
示例/路由器/dummy.js
export default function (context) {
return {
path: '/dummie',
beforeEnter (to, from, next) {
const { $dummie } = context.router
const msg = $dummie.sayHello({ name: to.params.name })
if (msg.length > 50) {
next('/hello-long-name')
} else {
next('/hello-short-name')
}
}
}
}
25 自定义 Quasar 组件
对于这个任务,我将使用@toby-mosque/utils
扩展,但我不会在不使用扩展的情况下显示等效代码,因为它涉及一个非常复杂的transparent wrapper
,其中一个小错误可能会导致难以追踪的错误或不需要的行为。
对于这个演示,我们将只定制QInput
,但我们可以定制任何组件,包括那些通过扩展安装的组件。
第一步是创建一个boot,这里我们称之为brand
quasar new boot brand
QPANC.App/quasar.config.js
module.exports = function (ctx) {
return {
boots: [
'brand'
]
}
}
QPANC.App/src/boot/inject.js
import { factory } from '@toby.mosque/utils'
import inject from './inject'
import { QInput } from 'quasar'
// "async" is optional
export default inject(({ Vue }) => {
const brand = {}
brand.input = Vue.observable({
/*
style: {
'font-size': '12px'
},
class: {
'custom-input': true
},
*/
props: {
outlined: true
}
})
factory.reBrand('q-input', QInput, brand.input)
return {
brand
}
})
对象brand
将被注入到componentes
和stores
中,所以我们以后可以访问它。
input
属性是Vue.observable
,对它的任何更改都会反映到使用它的组件上。input
只是一个名字,它可以是任何东西。
factory.reBrand
负责将brand.input
注入所有q-input
。它只会使用属性style
、class
和props
,其中这些属性将被注入到相应组件的style
、class
和props
中,这些属性都不是强制性的。
如果您现在运行应用程序,您将看到所有输入都将具有属性:outlined="true"
[](https://res.cloudinary.com/practicaldev/image/fetch/s--bkleUz4B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/n7aeea8sam0tar3o6euu.png)
现在,让我们修改上面的例子,使用Dark Mode
,在dark
模式下输入应该是filled
,在light
模式下输入应该是outlined
QPANC.App/src/boot/inject.js
import { factory } from '@toby.mosque/utils'
import inject from './inject'
import { QInput, Dark } from 'quasar'
// "async" is optional
export default inject(({ Vue }) => {
const brand = {}
brand.input = Vue.observable({
/*
style: {
'font-size': '12px'
},
class: {
'custom-input': true
},
*/
props: {
filled: Dark.isActive
outlined: !Dark.isActive
}
})
factory.reBrand('q-input', QInput, brand.input)
return {
brand
}
})
这里的问题是Dark.isActive
仅用作brand.input
的初始值,但是当Dark.isActive
更改时,它不会传播到brand.input
。
所以我们在App.vue
中需要一个watch
。
QPANC.App/src/App.vue
export default {
name: 'App',
watch: {
'$q.dark.isActive' () {
this.$brand.input.props.filled = this.$q.dark.isActive
this.$brand.input.props.outlined = !this.$q.dark.isActive
}
}
}
最后,一些印刷品:
[](https://res.cloudinary.com/practicaldev/image/fetch/s--q_85bLxG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/f02bpj2wrvsrav1g4dsk.png)
[](https://res.cloudinary.com/practicaldev/image/fetch/s--ubttai1S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/xukf5vxur4h2y3s85haq.png)
25 Cookie 持久性
由于这是一个SSR
应用程序,一些数据会自然地保存在客户端,例如Token JWT
、主题和首选语言。
但是,其中一些数据需要在服务器端访问,否则无法检索,我们将不得不使用 Cookie。
第一步是激活负责读取 Cookie 的插件。
QPANC.App/quasar.config.js
module.exports = function (ctx) {
return {
framework:
plugins: [
'Cookies'
]
}
}
}
现在,我们将为 vuex 添加一个插件,在本例中为vuex-persistedstate
yarn add vuex-persistedstate
现在添加引导persist
,不要让它添加到quasar.config.js
>boots
,在引导axios
和i18n
之前添加它是至关重要的。
quasar new boot persist
QPANC.App/quasar.config.js
module.exports = function (ctx) {
return {
boots: [
'persist',
'i18n',
'axios'
]
}
}
在编码 bootpersist
之前,我们需要创建一个小服务,该服务将负责为用户检测推荐的语言。
QPANC.App/src/services/locales.js
const locales = ['en-us', 'pt-br']
const regions = {
en: 'en-us',
pt: 'pt-br'
}
const fallback = regions.en
const detectLocale = function () {
if (process.env.CLIENT) {
const locale = navigator.language.toLowerCase()
if (locales.includes(locale)) {
return locale
}
const region = locale.split('-')[0]
if (region in regions) {
return regions[region]
}
return regions.en
} else {
return fallback
}
}
export {
locales,
regions,
fallback,
detectLocale
}
现在,让我们开始吧:
QPANC.App/src/boot/persist.js
import { Cookies, Quasar } from 'quasar'
import createPersistedState from 'vuex-persistedstate'
const persistState = function ({ name, store, storage }) {
createPersistedState({
key: name,
paths: [name],
filter ({ type }) {
return type.startsWith(name)
},
storage
})(store)
}
export default function ({ store, ssrContext }) {
const cookies = process.env.SERVER
? Cookies.parseSSR(ssrContext)
: Cookies
const cookieStorage = {
getItem (key) {
return JSON.stringify(cookies.get(key))
},
setItem (key, value) {
cookies.set(key, value, { path: '/' })
},
removeItem (key) {
cookies.remove(key, { path: '/' })
}
}
persistState({ name: 'app', store, storage: cookieStorage })
if (process.env.CLIENT) {
// persistState({ name: 'local', store, storage: window.localStorage })
store.commit('app/localeOs', detectLocale())
}
}
关于正在做的事情的一些细节:
persistState({ name: 'app', store, storage: cookieStorage })
我们指示vuex-persistedstate
将整个app
模块保存在Cookie
中
if (process.env.CLIENT) {
// persistState({ name: 'local', store, storage: window.localStorage })
}
如果注释被删除,我们是在指示vuex-persistedstate
将整个local
模块持久化到localStorage
if (process.env.CLIENT) {
store.commit('app/localeOs', detectLocale())
}
我们正在更新localeOs
,使其等于可用的locale
,最接近浏览器使用的语言,这将是应用程序语言,以防用户也未指定localeUser
。
但是,需要记住的是,客户端的代码是在服务器上执行之后才执行的,因此,在第一次请求中,服务器将始终使用默认语言,在这种情况下为英语(可在quasar.config.js > framework > lang
中配置)。
这样,在第一次请求时,应用程序将使用默认语言加载,并在页面加载后切换到浏览器通知的语言。
现在,让我们创建我们的模块app
QPANC.App/src/store/app.js
import { factory } from '@toby.mosque/utils'
class AppStoreModel {
constructor ({
token = '',
localeOs = '',
localeUser = ''
} = {}) {
this.token = token
this.localeOs = localeOs
this.localeUser = localeUser
}
}
const options = {
model: AppStoreModel
}
export default factory.store({
options,
getters: {
locale (state) {
return state.localeUser || state.localeOs
}
}
})
export { options, AppStoreModel }
由于这是一个全局模块,请不要忘记在QPANC.App/src/store/index.js
上注册它
QPANC.App/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import app from './app'
Vue.use(Vuex)
export default function (context) {
const Store = new Vuex.Store({
modules: {
app
},
strict: process.env.DEV
})
return Store
}
更多推荐
所有评论(0)