开始使用Vue

前期:这份文件是工作草案,还远未完成。随着时间的推移,我们将在Vue上做更多的工作,从而改进这一点。

开发工作流程

要了解如何在Matomo插件中构造和构建Vue模块,请参阅使用Matomo的UI指南的相关部分

开发人员的概念

单向数据流

Vue,像大多数其他现代前端框架一样,实施了一个名为“单向数据流”的重要概念,这基本上意味着通过应用程序对数据流的一个方向进行更改;应用程序的某个部分的更改不会隐式地影响应用程序的其他部分。

在实践中,这可以从组件如何将数据传递给其他组件中看到。父组件将数据作为属性传递给子组件,并且不允许子组件对该数据进行更改,因此子组件不能隐式地影响父组件。

当子组件需要将数据回传给父组件时,它会发出带有新数据的事件。父组件接收事件并对数据进行处理,这可能包括修改传递给子组件的数据。

这个循环是Vue等前端框架的核心机制。

组件状态与应用程序状态

Vue允许我们创建状态驱动的UI组件。组件是根据它们显示和操作的数据定义的。这个状态被组件“拥有”,因为只有组件可以修改它。其他组件,甚至是将该状态作为属性提供的子组件,都不应该被允许或能够更改该状态。这允许我们在UI中强制执行一定程度的可预测性。

但是,有些状态不属于单个组件。它可能是需要在多个组件之间保持同步的状态(例如,提供多个位置查看通知的应用程序中的通知数量),或者是从固有的全局状态派生出来的某些东西(例如URL查询参数的值)。像这样的全局状态必须在组件之外定义,并由任何需要它的人使用。

在Matomo中,我们通过商店模式来实现这一点(参见https://v3.vuejs.org/guide/state-management.html#simple-state-management-from-scratch)。全局状态封装在类中,操作它们的操作也是如此。这些存储中的所有数据都存储为反应性()属性或裁判()值,并由商店公开计算()属性供Vue组件使用。使用它们的Vue组件会自动向该属性注册,这样当存储中的数据发生变化时,组件会自动更新自己。

例子:

从'vue'导入{响应式,计算};类MyStore{私有myState =反应({计数器:0,});readonly counter = computed(() => this.myState.counter);readonly isZero = computed(() => this.myState.counter === 0);增量(){this.myState.counter += 1;} decentation () {this.myState.counter -= 1;}}导出默认的MyStore();
 

实现存储模式的类应该:

  • 定义私有响应状态
  • 只提供对该状态的公共只读访问。这种只读访问应该是深度的,私有状态的任何部分都不应该被其他类修改。
  • 使用计算属性(而不是方法)返回派生数据
  • 为改变状态的逻辑提供公共方法

v字和键

最好的做法是始终提供:关键使用v-for指令时进行绑定,但对于新手来说,有时很难知道在这里具体使用什么,因此我们提供了一些指导方针。

属性本身用于惟一地标识v-for迭代遍历的集合中的项,这允许Vue识别对数组的就地修改何时发生变化。例如,如果组件在v-for语句中使用的数组中将一个项从一个位置移动到另一个位置,Vue可以看到位置的键发生了变化并触发重新呈现。

对于Matomo中的某些实体,有一个存储在数据库中的ID可以使用。例如,Site's有一个idsite, Goals有一个idgoal,等等。但是,并不是使用v-for使用的每个数组都具有具有唯一ID的项,例如Site的url列表。对于这样的数组,你有两个选择:

  • 在运行时在客户端生成一个唯一的ID
  • 或者直接使用索引(Matomo的首选解决方案)

使用数组的索引通常被认为是不好的做法,因为在这种情况下,当对数组进行适当的修改时,键不会改变,Vue也不会注意到。但是,如果数组被视为不可变的,并且避免就地修改,则可以使用更简单的解决方案。

换句话说,如果每次数组发生更改,就会创建并使用一个全新的数组实例,那么它就可以工作。

访问和更改URL

在Matomo中的url主要基于查询参数,路径和主机通常不使用。基本URL的搜索有一个查询字符串,URL哈希有另一个查询字符串。两者都用于确定查询参数值,哈希查询参数覆盖搜索参数。

在新的Vue代码中,可以通过MatomoUrl存储访问和更改URL查询参数。此存储区提供一个计算属性,命名为解析,方便查阅查询参数值。它还提供了一个方法,updateHash ()允许开发人员更改URL,从而可能加载一个新页面。

一个访问查询参数值并在需要时修改哈希的例子:

从'vue'导入{computed, readonly};import {MatomoUrl} from 'CoreHome';class GoalsStore{私有只读状态=反应({goals:{}, //映射idGoal =>目标。通过本例中未显示的ajax请求填写});readonly allGoals = computed(() => readonly(this.state).goals);readonly currentGoal = computed(() => {const idGoal = matomourl .parse .value.idGoal;if (idGoal && this.state.goals[idGoal]){返回只读(this.state.goals[idGoal]);}返回未定义的;});changeGoal(idGoal: number): void {MatomoUrl。updateHash({ // NOTE: updateHash will rewrite the entire hash, so it is important to include existing query parameters, // if you only want to overwrite one or a few parameters. ...MatomoUrl.parsed.value, idGoal, }); } }

观察URL中的变化

一般来说,在访问URL值时,首选依赖于创建绑定到Vue组件的计算属性,但有时有必要在每次URL直接更改时执行一些逻辑。要做到这一点,您可以使用Vue看()功能:

从'vue'导入{watch};watch(() => MatomoUrl.parsed。value, (newValue, oldValue) =>{//做一些创建副作用的事情});

AJAX请求

在TypeScript和Vue代码中的AJAX请求应该使用AjaxHelper由CoreHome插件导出的类。这个类有两个静态方法,你可以用它们来发出请求:获取而且帖子.唯一的区别是帖子有第二个参数POST参数,但你也可以指定这些参数在选项参数获取

Matomo发送的所有AJAX请求都是POST请求,以避免在浏览器中缓存token_auth值。

例子:

import {AjaxHelper} from 'CoreHome';interface ResponseType {id: number;名称:字符串;值:字符串;} let isLoading = true;AjaxHelper。获取( { param: 'value', arrayParam: [1, 2, 3], }, { // ... other AjaxHelper options ... postParams: { postValue: 'value 2', }, }, ).then((response) => { console.log(`Fetched ${response.name} with id = ${response.id}.`); }).finally(() => { isLoading = false; });

大部分的请求

您可以通过简单地将查询对象数组传递给fetch ().所有参数都将作为POST参数发送。

例子:

import {AjaxHelper} from 'CoreHome';AjaxHelper。获取<[ResponseType1, ResponseType2]>([ { method: 'MyPlugin.firstApiRequest', // ... }, { method: 'MyPlugin.secondApiRequest', // ... }, ]).then(([r1, r2]) => { // use r1, r2 });

使用Vue外部的Vue组件

有时有必要从不同的上下文中初始化和使用Vue组件,例如在树枝模板或原始HTML中。可以通过使用vue-entry属性和piwikHelper.compileVueEntryComponents ()方法(Matomo.helper.compileVueEntryComponents ()在Vue代码)。

注意:此属性必须由Matomo手动处理。Matomo的前端不会在vue条目元素被添加到DOM时自动扫描和注意(除非在页面加载时和显示小部件/报告页面时)。如果您正在编写手动插入从AJAX获得的HTML的代码,该代码可能具有vue-entry元素,则需要运行compileVueEntryComponents ()你自己在包含新HTML的元素上。

还要注意,如果您正在编写Vue代码,则通常不需要使用此特性,而只需直接使用其他Vue组件。

将此属性添加到HTML中,如下所示:

< div vue-entry = "并且。MyComponent" prop-value=""value for propValue property"" my-other-property="{"name": "the name"}" />

这将安装MyComponent导出的组件并且它会将属性值作为组件的初始prop值传递。所有属性值都应该是JSON编码的。

如果你的组件使用槽,你可以通过vue-components属性为你的槽内容添加一个组件列表:

< div vue-entry = "并且。MyComponent" vue-components="CoreHome.ProgressBar MyOtherPlugin.MyOtherComponent" >  

使用自定义npm包

如果你想使用Matomo默认没有安装的npm包,你可以使用Vue来定义插件的前端。要使用其他npm包,只需运行npm安装纱添加在插件目录下。

这将在插件根目录下的一个新的node_modules文件夹中安装依赖项,例如:插件/编写MyPlugin / node_modules.然后你可以像往常一样导入它,webpack会在查找它时正确地解析它。

如果还想包含类型,则必须提供自己的tsconfig。Json文件。它应该看起来像这样:

{"extends": "../../tsconfig. ". json", "compilerOptions": {"typeRoots": ["../../ node_modules @types ", "../../ 插件/ CoreVue /类型/ index.d。ts”、“。/ node_modules @types”),“类型”:[“jquery”、“my-new-dependency”,“……”]}}

您需要指定根tsconfig的类型和typeroot。json以及任何你想要添加的类型vue:构建命令为您的插件。

Baidu