通过 props 和 Vue 原型实例在不同组件之间共享数据状态
在前面的表单组件中,包含了一个作者字段,通常该字段的值就是当前登录用户的用户名,如果应用包含多个类似表单,每次都要手动填写有些麻烦,我们可否通过从外部传入或者全局共享变量来自动填充作者字段对应的输入框?
当然可以。
通过 props 从父作用域传递
从外部传入的话,使用前面 Vue 组件基本语法里介绍的 props 属性即可。
我们在视图层引入表单组件的父级作用域中,在 form-component
元素上设置一个 username
属性,通过 Blade 语法填充当前认证用户的用户名作为属性值,如果用户未认证的话,显示匿名用户:
<form-component username="{{ auth()->check() ? auth()->user()->name : '匿名用户' }}"></form-component>
然后在 FormComponent.vue
中通过 props 属性将其引入 Vue 组件,并将其作为 form.author
字段的默认值:
<script>
export default {
props: ['username'],
data() {
return {
form: new Form({
title: '',
author: this.username,
content: ''
})
}
},
...
接下来,就可以基于 Vue 框架的数据绑定完成将其填充到文章发布表单的作者字段输入框。
我们重新编译前端资源,刷新表单视图,就可以看到未认证的情况下,作者输入框默认填充了「匿名用户」:
如果是认证用户的话,则会填充对应的认证用户名:
注:laravel/ui 包默认提供了认证脚手架代码,运行
php artisan ui bootstrap --auth
即可自动生成,然后运行php artisan migrate
创建对应的用户表,就可以通过/register
路由在注册表单注册一个新用户并基于此用户进行登录认证了。
非常简单,不过,这种方式需要在每个引入 form-component
的地方设置 username
属性(当然,你可以通过 Blade 模板的组件和包含子视图功能规避同一个表单组件的重复设置,不过不同的表单组件还是要这么做),除此之外,我们还可以通过为 Vue 设置原型实例以便在每个 Vue 组件中共享数据状态。
添加 Vue 原型实例
引入 User 类
开始之前,我们在 resources/js
目录下新建一个 user.js
文件定义 User
类:
class User {
constructor(data) {
this.new(data);
}
new(data) {
Object.keys(data).forEach((field) => {
this[field] = data[field];
})
}
data() {
let data = {};
Object.keys(this).forEach((field) => {
data[field] = this[field];
});
return data;
}
get(field) {
return this[field];
}
set(field, value) {
this[field] = value;
}
}
export default User;
然后在 resources/js/app.js
中引入它。
window.User = require('./user').default;
这样,我们就可以在后续代码中直接使用 User
类了:
注册后端路由
为了初始化 User
实例,需要从后端接口读取用户数据,我们在 routes/web.php
注册这个 /user
路由,路由处理逻辑也非常简单,我们通过 PHP 的箭头函数直接返回当前认证用户的数据即可,如果未认证返回空数组:
Route::get('/user', fn() => auth()->check() ? auth()->user() : []);
你可以先在浏览器测试这个接口是否可以正常工作:
通过 Vue 原型实例共享全局变量
接下来,回到 resources/js/app.js
,我们在 Vue 组件初始化和挂载之前通过 axios
库异步读取后端 /user
接口数据,并将其赋值给 Vue.prototype.$user
:
window.User = require('./user').default;
axios.get('/user').then(resp => {
Vue.prototype.$user = new User(resp.data);
}).catch(error => {
console.log(error);
});
这样一来,我们就在 Vue 原型上新增了一个 $user
实例属性,后续就可以在所有组件中共享这个属性了,以 FormComponent.vue
组件为例,我们定义一个 mounted
钩子函数 基于 Vue.prototype.$user
初始化 form.author
字段值:
data() {
return {
form: new Form({
title: '',
author: '匿名用户',
content: ''
})
}
},
mounted() {
let timer = setInterval(() => {
if (this.$user) {
this.form.author = this.$user.get('name');
clearInterval(timer);
}
}, 100);
},
可以看到,在 Vue 组件中可以通过 this.$user
引用 Vue.prototype.$user
,由于 Vue.prototype.$user
是异步读取后端接口数据设置的,所以这里也定义了一个定时器,每隔 100ms 刷新下,读取到 $user
完成 form.author
字段初始化后,清除这个定时器。
最后,我们刷新表单视图,就可以看到这个作者字段刷新的过程:
如果引用的是一个静态的实例数据,则不需要编写这些异步代码,直接读取 Vue 原型实例数据即可。
小结
当然,关于组件之间的数据状态共享 Vue 官方还提供更加优雅的系统解决方案 —— Vuex,我们将在后续单页面应用实战中详细介绍它的使用。这篇教程的意义是对于非常小的功能,有时候没有必要引入 Vuex,我们可以基于 Vue 本身提供的一些基本语法来实现组件间的数据共享。
No Comments