经过 Laravel 建立一个 Vue 单页面应用(四)

文章转发自专业的Laravel开发者社区,原始连接:learnku.com/laravel/t/3…php

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

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

/users/:id/edit

复制代码

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

安装

在处理 Vue 组件以前,咱们须要定一个新的 API 接口来获取指定的用户,而后再定义一个接口来处理更新。ios

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

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":"znikolaus@example.org"
    }
}

复制代码

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

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class UserResource extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            '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>
      <form @submit.prevent="onSubmit($event)">
        <div class="form-group">
            <label for="user_name">Name</label>
            <input id="user_name" v-model="user.name" />
        </div>
        <div class="form-group">
            <label for="user_email">Email</label>
            <input id="user_email" type="email" v-model="user.email" />
        </div>
        <div class="form-group">
            <button type="submit">Update</button>
        </div>
    </form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      user: {
        id: null,
        name: "",
        email: ""
      }
    };
  },
  methods: {
    onSubmit(event) {
        // @todo form submit event
    }
  },
  created() {
      // @todo load user details
  }
};
</script>

复制代码

首先看下 template 部分:咱们在 div 中书写 <form> ,由于稍后咱们只须要在加载了 user 数据后展现 <form>

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

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

咱们准备编辑已经存在的用户,因此下一步会说明怎么获取路由中动态的  :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
<script>
import api from '../api/users';

export default {
  // ...
  created() {
      api.find(this.$route.params.id).then((response) => {
        this.loaded = true;
        this.user = response.data.data;
      });
  }
}
</script>

复制代码

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

如今往 data 中添加 loaded 属性,默认值为 false :

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

复制代码

因为咱们的组件在 created() 中加载数据,因此在组件加载数据时显示「加载」的提示消息:

<div v-if="! loaded">Loading...</div>
<form @submit.prevent="onSubmit($event)" v-else>
<!-- ... -->
</form>

复制代码

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

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

API速度很快,若是你要肯定 loading 提示正常工做,你须要使用 setTimeout 去延迟设置 user 属性:

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

复制代码

上面的代码会显示 loading 消息5秒,而后设置 loaded 和 user 属性。

更新用户

咱们将完成 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() 方法,传入从绑定表单中获取的 name 和 email 的值。

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

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

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

<div class="form-group">
  <button type="submit" :disabled="saving">Update</button>
</div>

复制代码

咱们在 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: ""
    }
  };
},

复制代码

下一步,咱们来修改 <template> 来展现 message :

<template>
  <div>
      <div v-if="message" class="alert">{{ message }}</div>
      <div v-if="! loaded">Loading...</div>
      <form @submit.prevent="onSubmit($event)" v-else>
        <div class="form-group">
            <label for="user_name">Name</label>
            <input id="user_name" v-model="user.name" />
        </div>
        <div class="form-group">
            <label for="user_email">Email</label>
            <input id="user_email" type="email" v-model="user.email" />
        </div>
        <div class="form-group">
            <button type="submit" :disabled="saving">Update</button>
        </div>
    </form>
  </div>
</template>

复制代码

最后,咱们在 UsersEdit.vue 文件底部为 alert 信息添加一些样式:

<style lang="scss" scoped>
$red: lighten(red, 30%);
$darkRed: darken($red, 50%);
.form-group label {
  display: block;
}
.alert {
    background: $red;
    color: $darkRed;
    padding: 1rem;
    margin-bottom: 1rem;
    width: 50%;
    border: 1px solid $darkRed;
    border-radius: 5px;
}
</style>

复制代码

如今,前端组件已经修改完毕,它能够处理表单的提交,并能在 API 成功执行以后同步更新模板。如今咱们须要转到后端来完成剩下的部分。

在 API 后端更新用户

咱们准备在 User 资源控制器上定义一个 update 方法来链接全部部分。咱们在服务端进行数据验证。但咱们暂时不会和前端对接。

第一步,咱们在 routes/api.php 中定义新的路由 PUT /api/users/{user}

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

复制代码

下一步,UsersController@update 方法会使用 request 对象来验证数据,并返回咱们要更新的数据。把下面的方法添加到 app/Http/Controllers/Api/UsersController.php 中:

public function update(User $user, Request $request)
{
    $data = $request->validate([
        'name' => 'required',
        'email' => 'required|email',
    ]);

    $user->update($data);

    return new UserResource($user);
}

复制代码

像 show() 方法那样,咱们使用隐式的模型绑定从数据库中加载用户数据。数据验证后,更新用户模型,并新建一个 UserResource ,返回更新过的模型。

成功的面向后端的请求会返回更新过的用户的数据(JSON格式),而后咱们用它更新 Vue 组件中的  this.user 属性。

{
  "data": {
    "id": 1,
    "name":"Miguel Boyle",
    "email":"hirthe.joel@example.org"
  }
}

复制代码

导航到编辑页面

咱们一直在直接请求 /users/:id/edit 页面, 可是,咱们没有在界面的任何地方添加路由。 在看到我是如何作到这一点以前,不妨本身尝试找出如何动态地导航到编辑页面。

这是我在 第二部分 建立了 UsersIndex.vue 模板,并为 /users 索引页上列出了每一个用户添加编辑连接的方式:

<ul v-if="users">
    <li v-for="{ id, name, email } in users">
        <strong>Name:</strong> {{ name }},
        <strong>Email:</strong> {{ email }} |
        <router-link :to="{ name: 'users.edit', params: { id } }">Edit</router-link>
    </li>
</ul>

复制代码

咱们从新构造循环中的  user 对象,以提供 idname 和 email 属性。咱们使用  <router-link/> 组件来引入咱们的命名的  users.edit 路由,使用 params 传递  id 参数。

为了更好地可视化 <router-link> 属性,面是咱们以前添加的 app.js 文件中的路由定义:

{
  path: '/users/:id/edit',
  name: 'users.edit',
  component: UsersEdit,
},

复制代码

若是您刷新应用程序或访问  /users 端点,您将看到以下内容:

将他们放在一块儿

若是你如今想编辑一个用户,在后台须要保存它并返回一个200的状态码来表示响应成功。 在 PUT 成功请求以后你应该会在两秒钟内看到如下内容:

你能够在下面看到完整的UsersEdit.vue组件内容:

<template>
  <div>
      <div v-if="message" class="alert">{{ message }}</div>
      <div v-if="! loaded">Loading...</div>
      <form @submit.prevent="onSubmit($event)" v-else>
        <div class="form-group">
            <label for="user_name">Name</label>
            <input id="user_name" v-model="user.name" />
        </div>
        <div class="form-group">
            <label for="user_email">Email</label>
            <input id="user_email" type="email" v-model="user.email" />
        </div>
        <div class="form-group">
            <button type="submit" :disabled="saving">Update</button>
        </div>
    </form>
  </div>
</template>
<script>
import api from '../api/users';

export default {
  data() {
    return {
      message: null,
      loaded: false,
      saving: false,
      user: {
        id: null,
        name: "",
        email: ""
      }
    };
  },
  methods: {
    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, 10000);
            this.user = response.data.data;
        }).catch(error => {
            console.log(error)
        }).then(_ => this.saving = false);
    }
  },
  created() {
      api.find(this.$route.params.id).then((response) => {
          setTimeout(() => {
            this.loaded = true;
            this.user = response.data.data;
          }, 5000);
      });
  }
};
</script>
<style lang="scss" scoped>
$red: lighten(red, 30%);
$darkRed: darken($red, 50%);
.form-group label {
  display: block;
}
.alert {
    background: $red;
    color: $darkRed;
    padding: 1rem;
    margin-bottom: 1rem;
    width: 50%;
    border: 1px solid $darkRed;
    border-radius: 5px;
}
</style>

复制代码

做业

用户信息更新成功后,咱们仅仅只是在两秒钟后重置该消息。 修改成已设置消息,并将用户重定向回先前的位置(如, /users 页)。

其次,在表单底部添加一个 返回取消 按钮,以放弃更新,并导航回上一页。

若是您认为不严谨,请在 UsersEdit 组件向 API 发送无效请求时显示验证错误。 成功提交表单后,清除错误消息。

下一步是什么

随着用户的更新,咱们将注意力转移到删除用户上。删除用户将有助于演示成功删除后以编程方式进行导航。如今,咱们将定义一个全局404页面,由于咱们具备用于编辑用户的动态路由。

若是您准备好了,请继续第五部分.

相关文章
相关标签/搜索