通过 Laravel 创建一个 Vue 单页面应用(四)

image

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t/34450

我们在第三部分中放弃构建真实的用户端,而学习使用 Vue 路由获取组件数据的新方式。现在我们准备将注意力转移到为用户创建 CRUD(增删改查)的功能上 —— 本教程将聚焦在编辑已存在的用户。

在处理第一个表单时,我们有机会了解如何定义动态 Vue 路由。我们的路由的动态部分是与用户数据记录匹配的用户 ID。对于编辑用户,Vue 路由如下所示:

/users/:id/edit

这个路由的动态部分是 :id 参数,它将取决于用户的 ID。我们将使用数据库中的 id 字段,但你也可以使用 UUID 或者其他的数据标识。

安装

在处理 Vue 组件之前,我们需要定一个新的 API 接口来获取指定的用户,然后再定义一个接口来处理更新。

打开 routes/api.php 路由文件,在获取全部用户的 index 路由下方添加下面的路由:

Route::namespace('Api')->group(function () {
    Route::get('/users', 'UsersController@index');
    Route::get('/users/{user}', 'UsersController@show');
});

理由 Laravel 内置的路由模型绑定,控制器方法将很简单明了。在 app/Http/Controllers/Api/UsersController.php 中添加下面的方法:

// app/Http/Controllers/Api/UsersController

public function show(User $user)
{
    return new UserResource($user);
}

/api/users/1 这样请求一个用户,将返回如下的 JSON

{
    "data": {
        "name": "Antonetta Zemlak",
        "email":"[email protected]"
    }
}

第三部分的 UserResource 需要包含 id 列,所以需要更新 app/Http/Resources/UserResource.php 添加 id 键。整个文件如下:

 $this->id,
            'name' => $this->name,
            'email' => $this->email,
        ];
    }
}

现在 /api/users/api/users/{user} 路由都将返回 id 字段,通过这个,可以在路由中区分用户。

定义 UsersEdit 组件

定义了 show 之后,我们接着定义 Vue 中的路由和相应的组件。新增相应的路由到 resources/js/app.js 中。下面是引入 UsersEdit 组件(尚未创建)和整个路由实例的代码片段:

import UsersEdit from './views/UsersEdit';

// ...

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/hello',
            name: 'hello',
            component: Hello,
        },
        {
            path: '/users',
            name: 'users.index',
            component: UsersIndex,
        },
        {
            path: '/users/:id/edit',
            name: 'users.edit',
            component: UsersEdit,
        },
    ],
});

我们在 routes 末尾新增了 users.edit 路由。

下一步, 我们需要在 resources/assets/js/views/UsersEdit.vue 中创建 UsersEdit 组件。代码如下:




首先看下 template 部分:我们在 div 中书写

,因为稍后我们只需要在加载了 user 数据后展示

有一个默认的 @submit 事件,我们定义了一个 onSubmit() 方法去处理它。最后需要提一下在 元素上的 v-model 属性,它和 data.users 对象一一对应。我们为 idname,和 email 设置了默认值。

现在你打开 /users/1/edit 应该看到一个空白的表单:

image

我们准备编辑已经存在的用户,所以下一步会说明怎么获取路由中动态的 :id ,在 UsersEdit.vue 中加载用户数据。

使用专用的模块获取用户详情

在我们在组件中加载用户数据之前,我们先定义一个额外的专用模块去处理 /api/users 的资源,包括查询所有用户,查询单个用户和更新用户。

第一步,创建一个新的文件夹来放置请求后端的模块。你可以用任意方式来创建这些文件。下面我们展示了在 Nix 下的命令:

mkdir -p resources/assets/js/api/
touch resources/assets/js/api/users.js

users.js 模块会暴露一些用来处理 /api/users 资源的方法。这个模块会尽可能的简单,但之后你可以在请求之前或者之后随意处理数据。这个文件用作可复用的API操作的存储库:

import axios from 'axios';

export default {
    all() {
        return axios.get('/api/users');
    },
    find(id) {
        return axios.get(`/api/users/${id}`);
    },
    update(id, data) {
        return axios.put(`/api/users/${id}`, data);
    },
};

现在我们可以使用同样的模块去获取所有用户,查询和更新单个用户:

// 获取所有用户
client.all().then((data) => mapData);

// 查询单个用户
client.find(userId);

目前为止,all() 方法不支持分页,需要你自己去实现分页,然后使用新的 all() 替换 UsersIndex.vue 组件中的方法。

在 UsersEdit 组件中加载用户数据

现在我们有了一个可复用但很简陋的api客户端,当编辑页面生成之后我们使用它来获取用户数据。

最初,我们在组件中添加了 created() 方法,现在我们可以在它里面获取用户的数据:

// UsersEdit.vue Component


created() 中,users.js 客户端使用 find() 方法返回了一个 Promise 对象。在 Promise 的回调中,我们设置了 loaded 属性(尚未创建)并设置了the user 属性。

现在往 data 中添加 loaded 属性,默认值为 false :

data() {
  return {
    loaded: false,
    user: {
      id: null,
      name: "",
      email: ""
    }
  };
},

由于我们的组件在 created() 中加载数据,所以在组件加载数据时显示「加载」的提示消息:

Loading...

刷新页面,你会看到一个简单的 Loading... 信息:

image

然后用户数据会显示在表单中:

image

API速度很快,如果你要确定 loading 提示正常工作,你需要使用 setTimeout 去延迟设置 user 属性:

api.find(this.$route.params.id).then((response) => {
    setTimeout(() => {
      this.loaded = true;
      this.user = response.data.data;
    }, 5000);
});

上面的代码会显示 loading 消息5秒,然后设置 loadeduser 属性。

更新用户

我们将完成 onSubmit() 方法,并用过 PUT /api/users/{user} 更新用户。

我们先完善 onSubmit() ,之后会转到后端处理数据库的更新:

onSubmit(event) {
  this.saving = true;

  api.update(this.user.id, {
      name: this.user.name,
      email: this.user.email,
  }).then((response) => {
      this.message = 'User updated';
      setTimeout(() => this.message = null, 2000);
      this.user = response.data.data;
  }).catch(error => {
      console.log(error)
  }).then(_ => this.saving = false);
},

我们通过用户 ID 调用 api.update() 方法,传入从绑定表单中获取的 nameemail 的值。

然后我们在 Promise 上链接一个回调方法,在 API 成功执行之后设置成功提示信息,并设置最新的用户数据。2000 毫秒后我们置空提示信息,这同样会隐藏模板中的消息。

目前为止,我们只是单纯的抓取所有错误并输出到控制台。未来,我们会回头重写错误(服务端错误或者验证错误)处理,但是现在,我们略过这一部分,专注在请求成功后的处理。

我们通过 this.saving 来确定我们是否在更新用户信息。我们给模板添加了 :disabled 属性,来避免重复提交,它能保证当我们在更新数据时提交按钮是禁止状态:

我们在 catch 之后另外链接了一个 then(),一旦 API 请求结束,就将 this.saving 设为 false 。我们需要重置这个属性为 false ,来确保我们可以再次提交数据。我们最后的 then() 使用了 _ 来表示这里有一个变量,但我们并不需要使用。你也可以定义一个使用空括号的箭头函数:

.then(() => this.saving = false);

我们在 data() 中新添了了两个属性:

data() {
  return {
    message: null,
    loaded: false,
    saving: false,
    user: {
      id: null,
      name: "",
      email: ""
    }
  };
},

下一步,我们来修改