vue响应式和双向数据绑定_将Vue.js数据绑定选项用于响应式应用程序

vue响应式和双向数据绑定

Vue.js is known as a "progressive framework for building user interfaces". There's a lot to unpack in this simple statement. It's easy to get started with Vue.js, with a minimal feature set, and then layer in more of the framework as you need it.

Vue.js被称为“用于构建用户界面的渐进框架”。 这个简单的语句有很多需要解压的地方。 只需最少的功能集即可轻松开始使用Vue.js,然后根据需要在更多框架中进行分层。

Unike React, it has full support for the MVC (Model View Controller) pattern out-of-the-box.

Unike React,它对现成的MVC(模型视图控制器)模式具有完全支持。

It's easier to use and grow with than Angular.

它比Angular更易于使用和扩展。

And, if you couldn't tell, I'm a little biased.

而且,如果您听不清,我有点偏颇。

Vue.js has full support for ECMA 6 (sometimes referred to as ES6 or ES2015). This means it's now very easy to make your applications modular as well as being able to support modern syntax, like: import.

Vue.js完全支持ECMA 6 (有时称为ES6或ES2015)。 这意味着现在可以很容易地将应用程序模块化,并能够支持现代语法,例如: import

Vue.js has a lot of options for managing reactive data-binding in your application. This is the ability for views to automatically update when models (data) change.

Vue.js有很多选项可用于管理应用程序中的响应数据绑定。 这是视图在模型(数据)更改时自动更新的功能。

In this post, you'll look at three different approaches, each with their own pros and cons. For each of the three approaches, you'll work with the same application: a progress bar that you can control with buttons. Then, you'll dig deeper into the last option with a more complex code example.

在本文中,您将研究三种不同的方法,每种方法各有优缺点。 对于这三种方法,您将使用相同的应用程序:可以使用按钮控制的进度条。 然后,您将通过一个更复杂的代码示例更深入地研究最后一个选项。

The application also uses the BootstrapVue project which gives us a set of easy tags and components to work with for demonstration. You'll make extensive use of the progress bar component.

该应用程序还使用BootstrapVue项目,该项目为我们提供了一组易于使用的标签和组件以进行演示。 您将广泛使用进度条组件。

Later, you'll make use of the Vuex library for formal management of data stores. You'll see how we can use these data stores to manage login and logout with Okta. First, let's look at: Why use Okta?

稍后,您将使用Vuex库对数据存储进行正式管理。 您将看到我们如何使用这些数据存储来管理Okta的登录和注销。 首先,让我们看一下:为什么使用Okta?

为什么要使用Okta进行身份验证? ( Why Use Okta for Authentication? )

While the example app in this post is focused on data binding, you're going to be building a real-world application. The application includes authentication using the OpenID Connect standard in conjunction with Okta and stores the results of the authentication in the advanced data store for Vue.js. Okta makes identity management easier, more secure, and more scalable than what you’re used to. Okta is an API service that allows you to create, edit, and securely store user accounts and user account data, and connect them with one or more applications. As a developer, I know that I need authentication. But, I’ve seen enough horror stories from breaches over the years that I am happy to not handle credentials directly. Our API enables you to:

尽管本文中的示例应用程序专注于数据绑定,但是您将要构建一个实际应用程序。 该应用程序包括使用OpenID Connect标准和Okta进行的身份验证,并将身份验证的结果存储在Vue.js的高级数据存储中。 Okta使身份管理比以前更轻松,更安全和可扩展。 Okta是一项API服务,允许您创建,编辑和安全地存储用户帐户和用户帐户数据,并将它们与一个或多个应用程序连接。 作为开发人员,我知道我需要身份验证。 但是,这些年来,我已经看到足够多的恐怖事件使我很高兴不直接处理凭据。 我们的API使您能够:

To get started on this tutorial, register for a forever-free developer account, or sign in if you already have one. When you’re done, come back to learn more about building a secure SPA app with Vue.js and Vuex.

要开始学习本教程,请注册一个永久免费的开发者帐户 ,或者如果已经拥有一个,请登录。 完成后,请返回以了解更多有关使用Vue.js和Vuex构建安全SPA应用程序的信息。

使用全局数据对象满足简单要求 ( Use a Global Data Object for Simple Requirements )

Using a global data object is straightforward and functional. It's very accessible and the easiest of the approaches you'll look at. It's also the most fragile approach and requires duplicated code.

使用全局数据对象既简单又实用。 它非常容易访问,并且是您将要研究的最简单的方法。 这也是最脆弱的方法,需要重复的代码。

Let's start by building and running the application. Clone the vue-data-binding-approaches GitHub project. Switch to the project folder, and run:

让我们从构建和运行应用程序开始。 克隆vue-data-binding-approaches GitHub项目。 切换到项目文件夹,然后运行:

cd basic
npm install
npm run serve

This runs a local instance of the application. Launch your browser and navigate to: http://localhost:8080.

这将运行应用程序的本地实例。 启动浏览器并导航到: http:// localhost:8080

For this section of the post, you'll be using the Global tab. Click Advance progress bar and you'll see the progress bar move. Click the Two tab, and you should see the progress bar at the same point. The progress bars on tabs One and Two are kept in sync automatically through a global data object.

对于帖子的这一部分,您将使用“ Global选项卡。 单击高级进度条 ,您将看到进度条移动。 单击“ 两个”选项卡,您应该在同一点看到进度栏。 选项卡“一”和“两”上的进度条通过全局数据对象自动保持同步。

Let's look at the code that backs the Global tab:

让我们看一下支持“全局”选项卡的代码:

In the main.js file, I define the global data object:

main.js文件中,我定义了全局数据对象:

export const globalData = {
  state: {
    max: 50,
    score: 0
  }
}

Notice that within the globalData object, there's a state object. Within state are the actual properties we want to make sure are reactive. Due to the limitations of modern JavaScript, Vue.js cannot detect property addition or deletion. As long as we preserve globalData.state, Vue.js will be able to keep variables inside it reactive.

请注意,在globalData对象中,有一个state对象。 在state是我们要确保是React性的实际属性。 由于现代JavaScript的限制,Vue.js无法检测到属性的添加或删除。 只要我们保留globalData.state ,Vue.js就能使其中的变量保持React性。

Let's take a look at the parts of the basic/src/components/data-binding-global/One.vue template which manipulates the progress bar and keeps the data in sync.

让我们看一下basic/src/components/data-binding-global/One.vue模板的各个部分,该模板可操纵进度条并使数据保持同步。

Starting with the <script> section first, you can see that the globalData object defined in main.js is imported into this template.

与启动<script>部分首先,你可以看到, globalData中定义的对象main.js导入到这个模板。

import { globalData } from '../../main'

The data function binds the globalData object to a local variable in this template:

data函数将globalData对象绑定到此模板中的局部变量:

data() {
    return {
        scoreState: globalData.state
    }
}

The advance and reset functions manipulate the values in the globalData object. This is done by using the local template reference, which "points" to the object within our data structure. This is what preserves the reactive nature of the data in the template and why we need to nest the data properties in globalData.

advancereset功能可操纵globalData对象中的值。 这是通过使用本地模板引用来完成的,该模板引用指向我们数据结构内的对象。 这就是保留模板中数据的React性的原因,以及为什么我们需要将数据属性嵌套在globalData

advance: function () {
    if (this.scoreState.score < this.scoreState.max) {
        this.scoreState.score += 10
    }
},
reset: function () {
    this.scoreState.score = 0
}

Tying it all together is the template section. Here's the progress bar:

将所有内容捆绑在一起是模板部分。 这是进度条:

<b-progress :max="scoreState.max" class="big-progress" show-progress>
    <b-progress-bar :value="scoreState.score"/>
</b-progress>

In the <b-progress> tag, the value for max is bound to the local template data object: scoreState.max. In the <b-progress-bar> tag, the value for value is bound to the local template data object: scoreState.score.

<b-progress>标记中, max的值绑定到本地模板数据对象: scoreState.max 。 在<b-progress-bar>标记中,value的value绑定到本地模板数据对象: scoreState.score

Finally, the template has buttons that when clicked call the advance and reset functions respectively to allow you to manipulate the progress bar.

最后,模板具有按钮,单击这些按钮可分别调用advancereset功能,以允许您操纵进度条。

basic/src/components/data-binding-global/Two.vue is almost an exact replica of One.vue. And, herein lies the issue with this approach: lots of repeated code.

basic/src/components/data-binding-global/Two.vue几乎是一个精确的复制品One.vue 。 而且,这种方法存在一个问题:大量重复的代码。

Try out the Global tab on the app and you should see that however far you advance the One tab within it, when you click the Two tab, the progress bar will be at the same location. This is proof that our global reactive data binding is working.

尝试使用该应用程序上的“ Global选项卡,您应该看到无论将One选项卡推进多远,单击“ Two选项卡时,进度条都将位于同一位置。 这证明我们的全局响应数据绑定正在运行。

We can improve on this code using the Storage Pattern to centralize initialization and logic code.

我们可以使用存储模式来改进此代码,以集中初始化和逻辑代码。

使用存储模式集中化数据更新逻辑 ( Use the Storage Pattern to Centralize Data Update Logic )

Click on the Storage Pattern of the app. You can use the controls and switch between the One and Two tabs. It looks just the same as the previous example. You'll see the difference as we dig into the code.

单击应用程序的Storage Pattern 。 您可以使用控件并在“ One和“ Two选项卡之间切换。 它看起来与前面的示例相同。 当我们深入研究代码时,您将看到差异。

In this version of the code, you use a centralized data store which includes not only the data object and initial states but also all the business logic.

在此版本的代码中,您将使用集中式数据存储,该存储不仅包括数据对象和初始状态,还包括所有业务逻辑。

Take a look at the basic/src/model/scoreStore.js:

看看basic/src/model/scoreStore.js

export default {
    state: {
        max: 50,
        score: 0
    },
    reset: function () {
        this.state.score = 0
    },
    score: function (score) {
        if (this.state.score < this.state.max) {
            this.state.score += score
        }
    },
    bumpScore: function () {
        this.score(10)
    }
}

There's still a state object that contains the internals of the data we want to be reactive in the application. There's also reset, score, and bumpScore functions containing the business logic that was repeated across components in the previous example.

仍然存在一个state对象,其中包含我们希望在应用程序中进行响应的数据的内部。 还有resetscorebumpScore函数,其中包含在上一个示例中跨组件重复的业务逻辑。

Now, take a look at the script section of basic/src/components/data-binding-storage/One.vue:

现在,看一下basic/src/components/data-binding-storage/One.vue的脚本部分:

import scoreStore from '../../model/scoreStore'

export default {
    name: 'One',
    data() {
        return {
            scoreState: scoreStore.state
        }
    },
    methods: {
        advance: () => scoreStore.bumpScore(),
        reset: () => scoreStore.reset()
    }
}

the data() function is very similar to what we saw before. You bind the data state from the central model store.

data()函数与我们之前看到的非常相似。 您从中央模型存储绑定数据state

The local functions in the methods section simply refer to functions from the central store.

方法部分中的本地函数仅引用中央存储中的函数。

There's a great reduction in the repeated code in the components and any additional logic can be added to the central store.

组件中的重复代码大大减少,并且可以将任何其他逻辑添加到中央存储。

This approach is robust and functional for simple projects. There are some shortcomings, however. The central store has no record of which component changed its state. Further, we want to evolve the approach where components can't directly change state, but rather trigger events that notify the store to make changes in an orderly manner. For more complex projects, it's useful to have a more formal data binding paradigm.

对于简单的项目,此方法是可靠且实用的。 但是有一些缺点。 中央存储没有哪个组件更改其状态的记录。 此外,我们希望发展一种方法,使组件不能直接更改状态,而只能触发通知商店以有序方式进行更改的事件。 对于更复杂的项目,拥有更正式的数据绑定范例很有用。

This is where Vuex comes in.

这就是Vuex进来的地方。

使用Vuex进行现代数据绑定 ( Use Vuex for Modern Data Binding )

Vuex is inspired by other modern state management frameworks, like flux. It accomplishes two primary goals:

Vuex受其他现代状态管理框架(例如flux )的启发。 它实现了两个主要目标:

  1. A centralized, reactive data store

    集中式React式数据存储
  2. Components cannot directly change state

    组件无法直接更改状态

Look at basic/src/model/scoreStoreVuex.js:

查看basic/src/model/scoreStoreVuex.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default
 new Vuex.Store({
    state: {
        max: 50,         score: 0
    },
    mutations: {
        bumpScore (state) {
            if (state.score < 50) {
                state.score += 10
            }
        },
        reset (state) {
            state.score = 0
        }
    }
  })

This time, you're instantiating a Vuex object. Similar to the storage pattern from earlier, we define a state object in the Vuex.Store. What's different here, is that there's a mutations section. Each function in this section receives state as a parameter. These functions are not called directly.

这次,您将实例化Vuex对象。 与之前的存储模式类似,我们在Vuex.Store定义一个状态对象。 这里的不同之处在于,有一个mutations部分。 本节中的每个函数都将state作为参数接收。 这些函数不直接调用。

You can see how changes to the datastore state are made by looking at basic/src/components/data-binding-vuex/One.vue. Take a look at the script section:

您可以通过查看basic/src/components/data-binding-vuex/One.vue来了解如何更改数据存储状态。 看一下script部分:

import scoreStoreVuex from '../../model/scoreStoreVuex'

export default {
    name: 'One',
    data() {
        return {
            scoreState: scoreStoreVuex.state
        }
    },
    methods: {
        advance: () => scoreStoreVuex.commit('bumpScore'),
        reset: () => scoreStoreVuex.commit('reset')
    }
}

Notice that the advance and reset functions call the commit function on scoreStoreVuex. The commit function takes a text parameter which is the name of one of the mutations we defined in the Vuex store.

请注意, advancereset函数在scoreStoreVuex上调用commit函数。 commit函数采用text参数,该参数是我们在Vuex存储中定义的突变之一的名称。

Once again, you can see that our progress meter is kept in sync across the One and Two views.

再一次,您可以看到我们的进度表在“ One Two视图和“ Two视图中保持同步。

The progress meter is a very simple example. In the next section, we'll examine more complex uses of Vuex.

进度表是一个非常简单的示例。 在下一节中,我们将研究Vuex的更复杂的用法。

使用Vuex进行高级数据绑定 ( Advanced Data Binding with Vuex )

Aside from ensuring that data elements cannot be directly changed, Vuex has a number of other features that adds to its usefulness. In this section, you'll examine store injection, a helper for computed fields and managing more complex data objects, like arrays and javascript objects.

Vuex除了确保不能直接更改数据元素外,还具有许多其他功能,可增加其实用性。 在本节中,您将研究商店注入,它是计算字段的助手,并管理更复杂的数据对象,例如数组和javascript对象。

Vuex商店注入 (Vuex Store Injection)

In this section, you use the vuex-advanced folder in the okta-vuejs-data-binding-example project.

在本节中,您将使用vuex-advanced -vuejs-data-binding-example项目中的vuex-advanced文件夹。

At the top level of your app, you can inject the Vuex store. This will make it available to all components in the project without needing to explicitly import it.

在应用程序的顶层,您可以注入Vuex商店。 这将使其可用于项目中的所有组件,而无需显式导入。

It looks like this:

看起来像这样:

const store = new Vuex.Store({
...
})

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

Now, in any component, you need only refer to: this.$store to work with the Vuex data store.

现在,在任何组件中,您仅需引用: this.$store即可使用Vuex数据存储。

Vuex计算字段 (Vuex Computed Fields)

Computed fields are a key feature of Vue.js in general. Vuex provides advanced functionality to hook into the store to capture changes and make it easy to update the view automatically.

通常,计算字段是Vue.js的关键功能。 Vuex提供了高级功能,可以挂接到商店中以捕获更改并使其易于自动更新视图。

The mapState is a helper wrapper that can be used for computed fields. It looks like this:

mapState是一个可用于计算字段的帮助程序包装器。 看起来像这样:

import { mapState } from 'vuex';

computed: mapState([
    'ary', 'obj'
])

This is a shorthand for referencing state.ary and state.obj from the Vuex store. With this setup, you can then reference the computed value in your template:

这是从Vuex存储中引用state.arystate.obj的简写。 通过此设置,您可以在模板中引用计算值:

<h1>{{ary}}</h1>

使用Vuex管理数组和对象 (Managing Arrays and Objects with Vuex)

In the basic section of this post, you were working with very simple values, like an integer for the progress meter.

在本文的basic部分中,您正在使用非常简单的值,例如进度表的整数。

Let's take a look at how to manage arrays and objects with Vue.js and Vuex.

让我们看一下如何使用Vue.js和Vuex管理数组和对象。

Because of the reactive nature of the data in the Vuex store, it's important that you don't delete or replace more complex objects and arrays. Doing so would break reactivity and updates would no longer be shown in views.

由于Vuex存储中的数据具有响应性,因此请勿删除或替换更复杂的对象和数组,这一点很重要。 这样做会破坏React性,并且更新将不再显示在视图中。

In the vuex-advanced application, you can add and delete elements from both arrays and objects.

vuex-advanced应用程序中,可以从数组和对象中添加和删除元素。

Take a look at the add and del functions in the Vuex store:

看一下Vuex存储中的add和del函数:

const store = new Vuex.Store({
  state: {
    ary: [],
    obj: {}
  },
  mutations: {
    addAry: function (state, elem) {
      state.ary.push(elem)
    },
    delAry: function (state) {
      state.ary.splice(-1, 1)
    },
    addObj: function (state, elem) {
      Vue.set(state.obj, elem.key, elem.value)
    },
    delObj: function (state, name) {
      Vue.delete(state.obj, name);
    }
  }
})

For arrays, use the push function to add elements and the `splice` function to remove elements.

对于数组,使用push函数添加元素,使用`splice`函数删除元素。

For objects, use the Vue.set to add elements and `Vue.delete` to remove elements.

对于对象,使用Vue.set添加元素,使用`Vue.delete`删除元素。

In either case, the original object is never destroyed, preserving reactivity.

无论哪种情况,都不会破坏原始对象,从而保留了React性。

使用Okta和Vuex通过OpenID Connect轻松登录 ( Use Okta and Vuex for Easy Login with OpenID Connect )

Now that you've seen various approaches for data binding with Vue.js, let's take a look at a practical application of Vuex.

现在,您已经了解了使用Vue.js进行数据绑定的各种方法,让我们看一下Vuex的实际应用。

In this section, you'll develop a small, Single Page App (SPA) that integrates with Okta for authentication.

在本节中,您将开发一个小型的单页应用程序(SPA),该应用程序与Okta集成以进行身份​​验证。

The app makes use of OpenID Connect, so let's start with a quick overview of this standard for authentication and identity management.

该应用程序利用了OpenID Connect,因此让我们从此标准的快速概述开始,以进行身份​​验证和身份管理。

五分钟的OpenID Connect概述 (A Five-Minute Overview of OpenID Connect)

OpenID Connect is an identity and authentication layer that rides on top of OAuth 2.0. In addition to “knowing” who you are, you can use OIDC for Single Sign-On.

OpenID Connect是位于OAuth 2.0之上的身份和身份验证层。 除了“知道”您是谁之外,您还可以使用OIDC进行单点登录。

OIDC is built for web applications as well as native and mobile apps. It’s a modern approach to authentication that was developed by Microsoft, Google and others. It supports delegated authentication. This means that I can provide my credentials to my authentication provider of choice (like Okta) and then my custom application (like a Vue.js app) gets an assertion in the form of an ID Token to prove that I successfully authenticated.

OIDC是为Web应用程序以及本机和移动应用程序构建的。 这是由Microsoft,Google和其他公司开发的一种现代身份验证方法。 它支持委托身份验证。 这意味着我可以将凭据提供给我选择的身份验证提供程序(例如Okta),然后我的自定义应用程序(例如Vue.js应用程序)将以ID令牌的形式获取一个断言,以证明我已成功进行身份验证。

OpenID Connect uses “flows” to accomplish delegated authentication. This is simply the steps taken to get from an unauthenticated state in the application to an authenticated state. For the SPA app, you'll use the implicit flow for obtaining an ID Token. Here's what the interaction looks like:

OpenID Connect使用“流”来完成委托身份验证。 这只是从应用程序中的未认证状态到已认证状态所采取的步骤。 对于SPA应用程序,您将使用隐式流程获取ID令牌。 交互如下所示:

When you click the Login button in the app, you're redirected to Okta to authenticate. This has the advantage of your app not being responsible for handling credentials. Once you've authenticated at Okta, you're redirected back to the app with an ID Token. The ID Token is a cryptographically signed JWT that carries identity information in its payload. The app can then extract user information from the token. Additionally, the app uses Vuex to store the ID Token, which can be used later to log out. To learn more about OAuth 2.0 and OIDC, check out these blog posts:

当您在应用程序中单击“ 登录”按钮时,您将被重定向到Okta进行身份验证。 这具有您的应用程序不负责处理凭据的优点。 在Okta进行身份验证后,您将使用ID令牌重定向回到应用程序。 ID令牌是经过加密签名的JWT ,在其有效负载中携带身份信息。 然后,该应用可以从令牌中提取用户信息。 此外,该应用程序使用Vuex存储ID令牌,以后可用于注销。 要了解有关OAuth 2.0和OIDC的更多信息,请查看以下博客文章:

为SPA应用设置Okta (Set Up Okta for the SPA App)

Head on over to https://developer.okta.com to create an Okta org.

前往https://developer.okta.com创建Okta组织。

Login to your Okta org. Click Applications on the top menu. Click Add Application. Click Single-Page App and click Next.

登录到您的Okta组织。 单击顶部菜单上的应用程序 。 单击添加应用程序 。 单击“ 页应用程序” ,然后单击“ 下一步”

Give your app a name. Change the Login redirect URIs field tohttp://localhost:8080. Click Done.

为您的应用命名。 将Login redirect URIs字段更改为http://localhost:8080 。 单击完成

There's one more thing we need to configure in order to support logout.

为了支持注销,我们还需要配置另一件事。

Click Edit. Uncheck Allow Access Token with implicit grant type (we will only be using the ID Token in this example). Click Add URI next to Logout redirect URIs. Enter: http://localhost:8080/.

点击编辑 。 取消选中具有隐式授予类型的“允许访问令牌” (在此示例中,我们将仅使用ID令牌)。 单击注销重定向 URI旁边的添加URI 。 输入: http://localhost:8080/

使用Vuex和Okta Auth Javascript库 (Use Vuex and the Okta Auth Javascript Library)

The okta-auth-js library includes support for OpenID Connect.

okta-auth-js库包含对OpenID Connect的支持。

You can add it to your Vue.js project like so:

您可以将其添加到您的Vue.js项目中,如下所示:

npm install @okta/okta-auth-js --save

Just like before, you configure Vuex in main.js

和以前一样,您可以在main.js配置main.js

const store = new Vuex.Store({
  state: {
    user: {},
    idToken: ''
  },
  mutations: {
    setUser: function (state, elem) {
      Vue.set(state.user, elem.key, elem.value);
    },
    setIdToken: function (state, value) {
      state.idToken = value;
    }
  }
});

In this case, the data store keeps information about the user and the raw JWT in idToken.

在这种情况下,数据存储将有关user和原始JWT的信息保留在idToken

The Home.vue file is the only component in this app. Okta will redirect back to this component both when you log in and when you log out.

Home.vue文件是此应用程序中的唯一组件。 在您登录和注销时,Okta都会重定向回该组件。

Here's the code to import the okta-auth-js library and set up some constants:

这是导入okta-auth-js库并设置一些常量的代码:

import OktaAuth from '@okta/okta-auth-js';

const ISSUER = 'https://{yourOktaDomain}/oauth2/default';
const CLIENT_ID = '{yourClientId}';
const REDIRECT_URI = 'http://localhost:8080';
var authClient;

The created function is run when the component is first created. In this function, the authClient is set up:

首次创建组件时,将运行created函数。 在此功能中,设置了authClient

created() {
  authClient = new OktaAuth({
    issuer: ISSUER,
    clientId: CLIENT_ID,
    redirectUri: REDIRECT_URI
  });
}

The template is very simple. It shows the user information (which will be empty if you're not logged in). It shows a Login button if you're not currently authenticated and a Logout button if you are already authenticated.

该模板非常简单。 它显示用户信息(如果您未登录,则为空)。 如果您当前未通过身份验证,则会显示一个登录按钮,如果您已经通过身份验证,则会显示一个注销按钮。

<template>
  <div>
    <h1>Data Binding with Vue.js</h1>
    <h3>User Info:</h3>
    <div class="div-centered">
      <codemirror :value="userStr" :options="cmOptions"></codemirror>
    </div>
    <b-button v-if="!user.claims" @click="login" variant="primary" class="m-1">
        Login</b-button>
    <b-button v-if="user.claims" @click="logout" variant="danger" class="m-1">
        Logout</b-button>
  </div>
</template>

The app uses CodeMirror to display the JSON representing the user information formatted, indented and with line numbers.

该应用程序使用CodeMirror来显示JSON,该JSON表示格式化,缩进并带有行号的用户信息。

Notice :value="userStr" in the <codemirror> tag. If you examine the computed section of the script, you can see how userStr is computed:

注意<codemirror>标记中的:value="userStr" 。 如果检查脚本的computed部分,则可以看到如何计算userStr

userStr() {
  return JSON.stringify(this.$store.state.user, null, '\t')
}

JSON.stringify is used so that codemirror can display the information properly. The important bit is: this.$store.state.user. This retrieves the bound value from the Vuex store.

JSON.stringify ,以便Codemirror可以正确显示信息。 重要的一点是: this.$store.state.user 。 这将从Vuex存储中检索绑定值。

When you first browse over to the app at http://localhost:8080, the view is pretty sparse:

当您首次浏览到位于http:// localhost:8080的应用程序时,视图非常稀疏:

When you click Login, you're redirected over to Okta:

当您点击Login时 ,您将被重定向到Okta:

Here's the login function in the methods section:

这是methods部分中的login功能:

login() {
  authClient.token.getWithRedirect({
    responseType: 'id_token',
    scopes: ['openid', 'email', 'profile']
  })
}

The options passed into getWithRedirect ensure that you get back an id_token as well as specifying some default scopes in the request.

传递给getWithRedirect的选项getWithRedirect确保您获取id_token以及在请求中指定一些默认范围。

After you authenticate, Okta redirects back to http://localhost:8080. The mounted function is executed once the component is completely loaded and ready for action.

身份验证之后,Okta重定向回http://localhost:8080 。 一旦组件完全加载并准备就绪,便会执行已mounted功能。

async mounted() {
  // check for tokens from redirect
  if (location.hash) {
    var tokenInfo = await authClient.token.parseFromUrl();
    this.$store.commit(
        'setUser', {key: 'claims', value: tokenInfo.claims}
    );
    this.$store.commit('setIdToken', tokenInfo.idToken);
  }
}

The redirect from Okta includes the id_token value in the URL in the fragment section. It looks something like this:

来自Okta的重定向在片段部分的URL中包含id_token值。 看起来像这样:

http://localhost:8080/#id_token=eyJraWQiOiI3bFV0aGJyR2hWVmxVT2RzVldwWFQwaWdyUEVGOEl6ZUtvdW53ckZocWxzIiwiYWxnIjoiUlMyNTYifQ...

The mounted function first checks to see if there's a hash (#) in the location URL. Note: When you first browse to the app, there is no hash in the URL, so the if statement will not be entered.

mounted函数首先检查位置URL中是否有哈希( # )。 注意:首次浏览到应用程序时,URL中没有哈希,因此将不会输入if语句。

authClient.token.parseFromUrl() grabs the id_token from the url fragment, validates the cryptographic signature and extracts the json payload (the claims) from it.

authClient.token.parseFromUrl()从url片段中获取id_token,验证密码签名并从中提取json有效负载(声明)。

The next two lines save the parsed claims as well as the raw JWT in the Vuex store. As we saw before, the code is using this.$store.commit to take advantage of the mutations defined in the store.

接下来的两行将已解析的声明以及原始JWT保存在Vuex存储中。 如我们之前所见,代码正在使用this.$store.commit来利用商店中定义的突变。

Because of the data binding and computed values we setup earlier, the user info is now displayed in the component.

由于我们之前设置了数据绑定和计算值,因此用户信息现在显示在组件中。

Now when you click Logout, the app uses the information in the Vuex store to properly execute the logout operation and destroy your session with Okta.

现在,当您单击Logout时 ,该应用程序将使用Vuex存储中的信息正确执行注销操作并破坏与Okta的会话。

To log out with OIDC, you make a GET request of a /logout endpoint. You pass along the ID Token (as the raw JWT), as well as a redirect URI so that Okta can redirect back to the app after logout is complete. This is all set up in the logout function in the SPA app:

要使用OIDC注销,您需要发出/logout端点的GET请求。 您将传递ID令牌(作为原始JWT)以及重定向URI,以便Okta在注销完成后可以重定向回应用程序。 这都是在SPA应用程序的logout功能中设置的:

logout() {
  window.location.href = 
    ISSUER + '/v1/logout?id_token_hint=' + this.$store.state.idToken +
    '&post_logout_redirect_uri=' + REDIRECT_URI
}

This closes the loop on our SPA app, its use of the okta-auth-js library in conjunction with Vuex to manage data stores and how that data is bound to the component.

这将关闭SPA应用程序上的循环,将okta-auth-js库与Vuex结合使用以管理数据存储以及如何将数据绑定到组件。

选择最佳的Vue.js数据绑定方法 ( Pick the Optimal Vue.js Data Binding Approach )

All the code for this post can be found on Github.

这篇文章的所有代码都可以在Github上找到。

In the simplest cases, a global data store may suit your needs. Even for more complex applications, the storage pattern may suffice. I've written a number of Vue.js applications that are in production that use the storage pattern. This includes the online version of the Zork game that teaches you a little about OAuth 2.0.

在最简单的情况下,全局数据存储可能满足您的需求。 即使对于更复杂的应用程序,存储模式也足够了。 我已经编写了许多使用存储模式的Vue.js应用程序。 这包括Zork游戏的在线版本,该版本向您介绍了OAuth 2.0的一些知识。

Vuex offers a tradeoff between slightly more complex code and a high degree of stability and testability. Vuex makes it easy to inject the data store into your components using this.$store and ensures that data cannot be directly updated by components.

Vuex在稍微复杂一些的代码与高度的稳定性和可测试性之间进行权衡。 Vuex可以使用this.$store轻松将数据存储注入到组件中,并确保组件无法直接更新数据。

As is almost always the case, you'll need to pick the approach that makes the most sense for your use-case.

与几乎所有情况一样,您需要选择最适合您的用例的方法。

了解有关Vue.js和安全用户管理的更多信息 ( Learn More About Vue.js and Secure User Management )

Okta's written a Vue.js integration that makes integrating with Okta for secure auth a snap. It's part of our open-source javascript OpenID Connect library. You can go directly to the Vue.js integration as well.

Okta编写了Vue.js集成,从而使与Okta集成以实现安全身份验证变得轻而易举。 它是我们的开源javascript OpenID Connect库的一部分。 您也可以直接进入Vue.js集成。

At Okta, we say: friends don't let friends build auth! If you're working on a project that requires secure, reliable authentication and authorization, get a free developer account from Okta.

在Okta,我们说:朋友不要让朋友建立auth! 如果您正在从事需要安全,可靠的身份验证和授权的项目,请从Okta获得免费的开发者帐户。

Here are some more Vue.js posts that might interest you:

以下是一些您可能感兴趣的Vue.js帖子:

Check out the Okta Developer YouTube channel. You can follow us on social @oktadev

查看Okta Developer YouTube频道。 您可以关注我们的社交@oktadev

翻译自: https://scotch.io/tutorials/use-vuejs-data-binding-options-for-reactive-applications

vue响应式和双向数据绑定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值