开源软件门户的前端开发:分享经验

关于如何为俄罗斯最大的雇主创建门户解决方案文章第一部分中,后端描述了该体系结构。在本文中,我们将转到前端。



如第一部分所述,我们的主要目标是开发一个易于扩展和维护的平台。

可重用性该

前端大部分是用Vue.js编写的,并且由于整个门户被划分为Portlet,因此每个Portlet是一个单独的Vue实例,具有自己的Vuex,Vue Router和组件。每个这样的实例都移动到其自己的存储库中。

由于portlet在其存储库中,因此出现了一个问题,即如何不为不同的portlet写很多相同类型的代码。为了解决此问题,我们将所有可重用的内容转移到一个单独的存储库中,然后通过.gitmodules连接。目前有两个这样的子模块。

一个存储通用功能:这些是通用组件,服务,常量等。我们有一个称为Vue-common的模块。

第二个子模块包含组装设置,它存储webpack的配置以及组装过程中所需的加载程序和帮助程序。该模块称为Vue-bundler。

为了方便使用API​​,REST方法也分为常规方法和本地方法。在Vue-common中,引入了用于获取门户网站用户列表,管理方法,对门户网站文件系统的访问权等的方法。所有API端点都移到了在入口点注册并连接到Vue实例的单独服务。然后它们可以在应用程序中的任何位置使用。

每个单独的服务都在插件中注册。Vue具有用于连接插件的内置使用功能。此处阅读有关Vue插件的更多信息

插件本身是这样初始化的:

class Api {
    constructor () {
        //  http ,   
        this.instance = instance

        //     
       //     this,      http 
        Object.keys(commonServices).forEach(name => commonServices[name](this))
        
        //     
	requireService.keys().forEach(filename => requireService(filename).default(this))
    }

    install () {
	Vue.prototype.$api= this
    }
}

export default new Api()

除了初始化:

  1. http客户端实例已创建。设置我们的后端和标头的baseURL

    const instance = axios.create({
    	baseURL: '/example/api',
    	responseType: 'json',
    	headers: {
    		'Content-Type': 'application/json',
    		'Cache-Control': 'no-cache',
    		'Pragma': 'no-cache',
    	}
    })
                    backend   ,   axios.

  2. 创建的服务可自行存储请求

    // api -   http 
    export default api => {
    	api.exampleService= {
    		exampleGetRequest(params) {
    			return api.instance.request({
    				method: 'get',
    				url: `example/get`,
    				params
    			})
    		},
    		examplePostRequest(data) {
    			return api.instance.request({
    				method: 'post',
    				url: `example/post`,
    				data
    			})
    		},
    	}
    }
    

    通常,仅创建此类服务就足够了,并且已经为Api类中的每个portlet注册了该服务
  3. 已注册常规和本地服务

         const requireService = require.context('./service', false, /.service.js$/)
    

在组件中,它们的使用非常简单。例如:

export default {
	methods: {
		someMethod() {
    			this.$api.exampleService.exampleGetRequest()
}
}
}

如果您需要在应用程序外部发出请求,则可以执行以下操作:

//    (@ -     )
import api from ‘@/api’

//        
api.exampleService.exampleGetRequest()

缩放

如上所述,为每个门户网站收集一个单独的捆绑包,每个捆绑包都有自己的入口点。在每个组件中,都注册了组件和资产,配置了用于本地开发的授权,并连接了插件。

组件在本地和通用的每个应用程序中都进行了全局注册。

组件注册如下所示:

import _ from “lodash”

const requireComponent = require.context('@/components', true, /^[^_].+\.vue$/i)

requireComponent.keys().forEach(filename => {
    const componentConfig = requireComponent(filename)

    // Get PascalCase name of component
    const componentName = _.upperFirst(
        _.camelCase(/\/\w+\.vue/.exec(filename)[0].replace(/^\.\//, '').replace(/\.\w+$/, ''))
    )

    Vue.component(componentName, componentConfig.default || componentConfig)
})

有时,对于我们正在开发的门户来说,添加独特的功能是必要的,为此,您必须编写对其唯一的组件,或者只是以不同的方式实现组件。在单独的文件夹中创建一个组件就足够了,例如/ components-portal / *门户名称* / *。Vue,然后将其注册到所需的入口点,而不是为一个文件夹而是为多个文件夹添加require.context。

const contexts = [
    require.context('@/components', true, /^[^_].+\.vue$/i),
   require.context('@/components-portal/example', true, /^[^_].+\.vue$/i)
]

contexts.forEach(requireComponent => {
    requireComponent.keys().forEach(filename => {
        const componentConfig = requireComponent(filename)

        // Get PascalCase name of component
        const componentName = _.upperFirst(
            _.camelCase(/\/\w+\.vue/.exec(filename)[0].replace(/^\.\//, '').replace(/\.\w+$/, ''))
        )

        Vue.component(componentName, componentConfig.default || componentConfig)
    })
})

如果您为特定门户下的组件设置的名称与组件的常规库中的名称相同,则将其简单地重写为对象的属性并将用作该门户的组件。

诸如svg图标之类的资产也在全球范围内注册。我们使用svg-sprite-loader从svg图标创建一个精灵,然后通过<use:xlink:href =“#* icon name *” />使用

它们,它们的注册方式如下:

const requireAll = (r) => r.keys().forEach(r)

const requireContext = require.context('@/assets/icons/', true, /\.svg$/)

requireAll(requireContext)

为了不仅扩展功能,而且扩展组件样式,我们实现了一种机制,用于更改特定门户的样式。单文件组件在<style>标记中指定样式,并且默认情况下使用。为了实现特定门户网站的样式,您需要在另一个标签中注册它们

All Articles