vue js 对象下的原型
by Neo Ighodaro
由新Ighodaro
如何使用Vue.js和Pusher创建实时原型反馈应用程序 (How to create a realtime prototype feedback app using Vue.js and Pusher)
Here is a screen recording of what our application will be able to do once we are done building it:
这是完成应用程序构建后的应用程序屏幕截图:
我们将需要构建我们的应用程序的要求 (Requirements we will need to build our application)
Before we get started, we need to have a few things in place first. Some of the requirements are as follows:
在开始之前,我们需要首先做好一些准备。 一些要求如下:
Knowledge of PHP & the Laravel framework.
了解PHP和Laravel框架。
- Knowledge of JavaScript (ES6). JavaScript知识(ES6)。
- Knowledge of Vue.js. 了解Vue.js。
- PHP 7.0+ installed locally on your machine. PHP 7.0+在您的计算机上本地安装。
Laravel CLI installed locally.
Laravel CLI在本地安装。
Composer installed locally.
Composer在本地安装。
NPM and Node.js installed locally.
NPM和Node.js本地安装。
A Pusher application. Create one on pusher.com.
Pusher应用程序。 在pusher.com上创建一个。
Once you have verified that you have the above requirements, we can start creating our application.
确认您具有上述要求后,我们就可以开始创建应用程序了。
设置我们的原型反馈应用程序 (Setting up our prototype feedback application)
Let us get started with setting up our application. Create a new Laravel application using the command below:
让我们开始设置应用程序。 使用以下命令创建一个新的Laravel应用程序:
$ laravel new your_application_name
When the installation is complete, cd
to the application directory. Open the .env
file and let us make a couple of changes in the file.
安装完成后, cd
到应用程序目录。 打开.env
文件,让我们在文件中进行一些更改。
设置我们的数据库和迁移 (Setting up our Database and Migrations)
The first thing to do is set up our database and create its migrations. Let’s start by setting up the database. Replace the configuration items below:
首先要做的是建立数据库并创建其迁移。 让我们从设置数据库开始。 替换以下配置项:
DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=homesteadDB_USERNAME=homesteadDB_PASSWORD=secret
with:
与:
DB_CONNECTION=sqlite
This will now make the application use SQLite as its database choice. In your terminal, run the command below to create a new SQLite database:
现在,这将使应用程序使用SQLite作为其数据库选择。 在您的终端中,运行以下命令以创建新SQLite数据库:
$ touch database/database.sqlite
Now let’s create some migrations which will create the required tables to the database. In your terminal, run the following command to create the migrations we will need:
现在,让我们创建一些迁移,这些迁移将创建数据库所需的表。 在您的终端中,运行以下命令来创建我们将需要的迁移:
$ php artisan make:model Photo --migration --controller$ php artisan make:model PhotoComment --migration
The above command will create a model and then the --migration
and --controller
flags will instruct it to create a migration and a controller alongside the model.
上面的命令将创建一个模型,然后--migration
和--controller
标志将指示它创建迁移,并在模型旁边创建一个控制器。
For now, we are interested in the Model and the migration. Open the two migration files created in the ./database/migrations
directory. First, we’ll edit the CreatePhotosTable
class. Replace the content of the up
method with the following below:
目前,我们对模型和迁移感兴趣。 打开在./database/migrations
目录中创建的两个迁移文件。 首先,我们将编辑CreatePhotosTable
类。 用以下内容替换up
方法的内容:
public function up(){ Schema::create('photos', function (Blueprint $table) { $table->increments('id'); $table->string('url')->unique(); $table->string('image')->unique(); $table->timestamps(); });}
This will create the photos
table when the migrations are run using the artisan command. It will also create new columns inside the table, as specified above.
使用artisan命令运行迁移时,这将创建photos
表。 如上所述,它还将在表内创建新列。
Open the second migration class, CreatePhotoCommentsTable
, and replace the up
method with the contents below:
打开第二个迁移类CreatePhotoCommentsTable
,然后用以下内容替换up
方法:
public function up(){ Schema::create('photo_comments', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('photo_id'); $table->text('comment'); $table->integer('top')->default(0); $table->integer('left')->default(0); $table->timestamps(); $table->foreign('photo_id')->references('id')->on('photos'); });}
This will create the table photo_comments
when the migration is run, and will also create a foreign key to the photos
table.
运行迁移时,这将创建表photo_comments
,还将创建photos
表的外键。
Now go to your terminal and run the command below to run the migrations:
现在转到终端并运行以下命令来运行迁移:
$ php artisan migrate
This should now create the database tables.
现在,这应该创建数据库表。
设置模型 (Setting up the models)
Now that we have run our migrations, we need to make some changes to our model file so that it can work better with the table.
现在,我们已经运行了迁移,我们需要对模型文件进行一些更改,以使其可以更好地与表一起使用。
Open the Photo
model and replace the contents with the following:
打开“ Photo
模型并将内容替换为以下内容:
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Photo extends Model{ protected $with = ['comments']; protected $fillable = ['url', 'image']; public function comments() { return $this->hasMany(PhotoComment::class); }}
In the above, we have added the fillable
property which stops us from having mass assignment exceptions when trying to update those columns using Photo::create
. We also set the with
property which just eager loads the comments
relationship.
在上面的代码中,我们添加了fillable
属性,该属性使我们在尝试使用Photo::create
更新这些列时避免出现批量分配异常。 我们还设置了with
属性,它只是渴望加载comments
关系。
We have defined an Eloquent relationship comments
that just says the Photo
has many PhotoComments
.
我们已经定义了一个雄辩的关系comments
,该comments
仅表示该Photo
具有许多PhotoComments
。
Open the PhotoComment
model and replace the contents with the following:
打开PhotoComment
模型,并将内容替换为以下内容:
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class PhotoComment extends Model{ protected $fillable = ['photo_id', 'comment', 'top', 'left']; protected $appends = ['position']; public function getPositionAttribute() { return [ 'top' => $this->attributes['top'], 'left' => $this->attributes['left'] ]; }}
Just like the Photo
model, we have defined the fillable
property. We also use Eloquent accessors to configure a new property called position
which is then appended because we specified that in the appends
property.
就像Photo
模型一样,我们定义了fillable
属性。 我们还使用雄辩的访问器来配置一个称为position
的新属性,然后将其追加,因为我们在appends
属性中指定了该属性。
为我们的应用程序设置前端 (Setting up the frontend for our application)
The next thing we want to do is set up the front end of our application. Let’s start by installing a few NPM packages that we will need in the application. In your Terminal app, run the command below to install the necessary packages:
接下来要做的是设置应用程序的前端。 让我们从安装应用程序中需要的一些NPM软件包开始。 在终端应用程序中,运行以下命令以安装必要的软件包:
$ npm install --save laravel-echo pusher-js vue2-dropzone@^2.0.0$ npm install
This will install Laravel Echo, the Pusher JS SDK, and vue-dropzone. We will need these packages to handle realtime events later.
这将安装Laravel Echo , Pusher JS SDK和vue-dropzone 。 我们将需要这些软件包来稍后处理实时事件。
When the packages have been installed successfully, we can now start adding some HTML and JavaScript.
成功安装软件包后,我们现在可以开始添加一些HTML和JavaScript。
Open the ./routes/web.php
file and let’s add some routes. Replace the contents of the file with the contents below:
打开./routes/web.php
文件,然后添加一些路由。 用以下内容替换文件的内容:
<?phpRoute::post('/feedback/{image_url}/comment', 'PhotoController@comment');Route::get('/feedback/{image_url}', 'PhotoController@show');Route::post('/upload', 'PhotoController@upload');Route::view('/', 'welcome');
In the code above, we have defined a few routes. The first one will be handling POST
ed feedback. The second route will display the image that is to receive feedback. The third route will handle uploads, and the final route will display the homepage.
在上面的代码中,我们定义了一些路由。 第一个将处理POST
ed反馈。 第二条路线将显示要接收反馈的图像。 第三条路线将处理上传,最后一条路线将显示主页。
Now open the ./resources/views/welcome.blade.php
file and in there replace the contents with the following HTML code:
现在打开./resources/views/welcome.blade.php
文件,并在其中用以下HTML代码替换内容:
<!doctype html><html lang="{{ app()->getLocale() }}"><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" content="{{csrf_token()}}"> <title>Upload to get Feedback</title> <link href="https://fonts.googleapis.com/css?family=Roboto:400,600" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="{{ asset('css/app.css') }}"></head><body> <div id="app"> <div class="flex-center position-ref full-height"> <div class="content"> <uploadarea></uploadarea> </div> </div> </div> <script src="js/app.js"></script></body></html>
This is a simple HTML document, and if you look closely, you will see a reference to an uploadarea
tag which does not exist in HTML but is instead a Vue component.
这是一个简单HTML文档,如果仔细观察,您会看到对uploadarea
标记的引用,该标记在HTML中不存在,而是Vue组件。
Open the ./resources/assets/sass/app.scss
file and paste the following code below the import statements:
打开./resources/assets/sass/app.scss
文件,并将以下代码粘贴到import语句下面:
html, body { background-color: #fff; color: #636b6f; font-family: 'Roboto', sans-serif; font-weight: 100; height: 100vh; margin: 0;}.full-height { height: 100vh;}.flex-center { align-items: center; display: flex; justify-content: center;}.position-ref { position: relative;}.content { text-align: center;}.m-b-md { margin-bottom: 30px;}.dropzone.dz-clickable { width: 100vw; height: 100vh; .dz-message { span { font-size: 19px; font-weight: 600; } }}#canvas { width: 90%; margin: 0 auto; img { width: 100%; }}.modal { text-align: center; padding: 0!important; z-index: 9999; }.modal-backdrop.in { opacity: 0.8; filter: alpha(opacity=80);}.modal:before { content: ''; display: inline-block; height: 100%; vertical-align: middle; margin-right: -4px;}.modal-dialog { display: inline-block; text-align: left; vertical-align: middle;}.image-hotspot { position: relative; > img { display: block; height: auto; transition: all .5s; }}.hotspot-point { z-index: 2; position: absolute; display: block; span { position: relative; display: flex; justify-content: center; align-items: center; width: 1.8em; height: 1.8em; background: #cf00f1; border-radius: 50%; animation: pulse 3s ease infinite; transition: background .3s; box-shadow: 0 2px 10px rgba(#000, .2); &:after { content: attr(data-price); position: absolute; bottom: 130%; left: 50%; color: white; text-shadow: 0 1px black; font-weight: 600; font-size: 1.2em; opacity: 0; transform: translate(-50%, 10%) scale(.5); transition: all .25s; } } svg { opacity: 0; color: #cf00f1; font-size: 1.4em; transition: opacity .2s; } &:before, &:after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%; pointer-events: none; } &:before { z-index: -1; border: .15em solid rgba(#fff, .9); opacity: 0; transform: scale(2); transition: transform .25s, opacity .2s; } &:after { z-index: -2; background:#fff; animation: wave 3s linear infinite; } &:hover{ span { animation: none; background: #fff; &:after { opacity: 1; transform: translate(-50%, 0) scale(1); } } svg { opacity: 1; } &:before { opacity: 1; transform: scale(1.5); animation: borderColor 2s linear infinite; } &:after { animation: none; opacity: 0; } }}@-webkit-keyframes pulse{ 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); }}@keyframes pulse{ 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); }}.popover { min-width: 250px;}
Save the file and exit. Now let’s move on to creating our Vue components.
保存文件并退出。 现在让我们继续创建Vue组件。
使用Vue创建我们的原型反馈应用程序的功能 (Using Vue to create the functionalities of our prototype feedback app)
Open the ./resources/assets/js/app.js
file and in there we’ll create our Vue component. In this file find the line below:
打开./resources/assets/js/app.js
文件,然后在其中创建Vue组件。 在此文件中找到以下行:
Vue.component('example', require('./components/Example.vue'));
and replace it with:
并替换为:
Vue.component('uploadarea', require('./components/UploadArea.vue'));Vue.component('feedback', require('./components/FeedbackCanvas.vue'));
Now let’s create our first Vue component. In the ./resources/assets/js/components
directory create a file called UploadArea.vue
. In the new file paste in the following:
现在,让我们创建第一个Vue组件。 在./resources/assets/js/components
目录中,创建一个名为UploadArea.vue
的文件。 在新文件中粘贴以下内容:
<template> <dropzone ref="dropzone" id="dropzone" url="/upload" accepted-file-types="image/*" v-on:vdropzone-success="showImagePage" :headers="csrfHeader" class="flex-center position-ref full-height"> <input type="hidden" name="csrf-token" :value="csrfToken"> </dropzone></template><script>import Dropzone from 'vue2-dropzone';const LARAVEL_TOKEN = document.head.querySelector('meta[name="csrf-token"]').contentexport default { components: { Dropzone }, data() { return { csrfToken: LARAVEL_TOKEN, csrfHeader: { 'X-CSRF-TOKEN': LARAVEL_TOKEN } } }, methods: { showImagePage: (file, response) => { if (response.url) { return window.location = `/feedback/${response.url}`; } } }, mounted () { this.$refs.dropzone.dropzone.on('addedfile', function (file) { if (this.files.length > 1) { this.removeFile(this.files[0]) } }) }}</script>
In the template
section, we are simply using the Vue dropzone package to define an area through which files can be uploaded. You can view the documentation here.
在template
部分,我们仅使用Vue dropzone包定义一个可以上传文件的区域。 您可以在此处查看文档。
In the script
section, we get the Laravel CSRF token from the header of the page and import the Dropzone
component into our current Vue component.
在script
部分,我们从页面的标题中获取Laravel CSRF令牌,并将Dropzone
组件导入到我们当前的Vue组件中。
In the methods
property, we define a showImagePage
method that just redirects the user to the image page after the image has been successfully uploaded. In the mounted
method, we limit the dropzone file to allow one file upload at a time.
在methods
属性中,我们定义了showImagePage
方法,该方法仅在成功上传图像后将用户重定向到图像页面。 在mounted
方法中,我们限制dropzone文件,以允许一次上传一个文件。
Let us create our next Vue component. In the ./resources/assets/js/components
directory, create a new file called FeedbackCanvas.vue
and paste in the following:
让我们创建下一个Vue组件。 在./resources/assets/js/components
目录中,创建一个名为FeedbackCanvas.vue
的新文件,并粘贴以下内容:
<template> <div class="feedback-area"> <div class="content"> <div id="canvas"> <div class="image-hotspot" id="imghotspot"> <transition-group name="hotspots"> <a href="#" class="hotspot-point" v-for="(comment, index) in image.comments" v-bind:style="{ left: comment.position.left+'%', top: comment.position.top+'%' }" :key="index" @click.prevent data-placement="top" data-toggle="popover" :data-content="comment.comment" > <span> <svg class="icon icon-close" viewBox="0 0 24 24"> <path d="M18.984 12.984h-6v6h-1.969v-6h-6v-1.969h6v-6h1.969v6h6v1.969z"></path> </svg> </span> </a> </transition-group> <img ref="img" :src="'/storage/'+image.image" id="loaded-img" @click="addCommentPoint"> </div> </div> </div> <add-comment-modal :image="image"></add-comment-modal> </div></template>
We have defined the template
for our Vue component. This is the area where the image will be displayed and where feedback will be given.
我们已经为Vue组件定义了template
。 这是显示图像并提供反馈的区域。
Let’s break some parts of it down a little. The a
tag has a bunch of attributes set to it. The v-for
loops through each comment/feedback the image has.
让我们将其中的一些部分分解一下。 在a
标签有一堆设置为它的属性。 v-for
循环遍历图像的每个注释/反馈。
The v-bind:style
applies a style
attribute to the a
tag using the left
and top
properties of the comment/feedback. We also have the :data-content
, data-toggle
and data-placement
which Bootstrap needs for its Popovers.
v-bind:style
使用注释/反馈的left
和top
属性将style
属性应用于a
标签。 Bootstrap的Popovers还需要:data-content
, data-toggle
和data-placement
。
The img
tag has the @click
event that fires the function addCommentPoint
when an area of the image is clicked. And finally, there’s a Vue component add-comment-modal
that accepts a property image
. This component will display a form so anyone can leave a comment.
img
标签具有@click
事件,当单击图像的某个区域时,该事件会触发功能addCommentPoint
。 最后,还有一个Vue组件add-comment-modal
,它接受属性image
。 该组件将显示一个表单,因此任何人都可以发表评论。
In this same file, after the closing template
tag, paste in the following code:
在该文件的结束template
标记之后,粘贴以下代码:
<script> let AddCommentModal = require('./AddCommentModal.vue') export default { props: ['photo'], components: { AddCommentModal }, data() { return { image: this.photo } }, mounted() { let vm = this Echo.channel(`feedback-${this.photo.id}`) .listen('.added', (e) => { // Look through the comments and if no comment matches the // existing comments, add it if (vm.image.comments.filter((comment) => comment.id === e.comment.id).length === 0) { vm.image.comments.push(e.comment) $(document).ready(() => $('[data-toggle="popover"]').popover()) } }) }, created() { /** Activate popovers */ $(document).ready(() => $('[data-toggle="popover"]').popover()); /** Calculates the coordinates of the click point */ this.calculateClickCordinates = function (evt) { let rect = evt.target.getBoundingClientRect() return { left: Math.floor((evt.clientX - rect.left - 7) * 100 / this.$refs.img.width), top: Math.floor((evt.clientY - rect.top - 7) * 100 / this.$refs.img.height) } } /** Removes comments that have not been saved */ this.removeUnsavedComments = function () { var i = this.image.comments.length while (i--) { if ( ! this.image.comments[i]['id']) { this.image.comments.splice(i, 1) } } } }, methods: { addCommentPoint: function(evt) { let vm = this let position = vm.calculateClickCordinates(evt) let count = this.image.comments.push({ position }) // Show the modal and add a callback for when the modal is closed let modalElem = $("#add-modal") modalElem.data({"comment-index": count-1, "comment-position": position}) modalElem.modal("show").on("hide.bs.modal", () => vm.removeUnsavedComments()) } }, }</script>
? The*
*created**
and**mounted**
methods are hooks that are called automatically during the creation of the Vue component. You can learn about the Vue lifecycle here.? 吨他*
*created**
一个ND **mounted**
编制方法是被创建的Vue组件期间自动调用挂钩。 您可以 在这里获得有关Vue生命周期的信息。
In the mounted
method, we use Laravel Echo to listen to a Pusher channel. The channel name depends on the ID of the image currently being viewed. Each image will have broadcasts on a different channel based on the ID of the image.
在mounted
方法中,我们使用Laravel Echo收听Pusher频道。 频道名称取决于当前正在观看的图像的ID。 每个图像将基于图像的ID在不同的频道上进行广播。
When the added
event is triggered on the feedback-$id
channel, it looks through the available image.comments
and, if the comment broadcasted does not exist, it adds it to the comments array.
当在feedback-$id
通道上触发added
事件时,它将通过可用的image.comments
查找,如果广播的注释不存在,则将其添加到注释数组。
In the create
method, we activate Bootstrap popovers, define a function that calculates the coordinates of the click point, and we define a function that removes comments that have not been saved from the image.comments
array.
在create
方法中,我们激活Bootstrap弹出窗口,定义一个函数来计算单击点的坐标,并定义一个函数来删除尚未从image.comments
数组中保存的image.comments
。
Under methods
we define the addCommentPoint
method which calculates the click coordinates, and then launches a new Bootstrap modal which is going to be created in the add-comment-modal
Vue component.
在methods
我们定义addCommentPoint
方法,该方法计算点击坐标,然后启动一个新的Bootstrap模态,该模态将在add-comment-modal
Vue组件中创建。
For Laravel Echo to work, we need to open the ./resources/assets/js/bootstrap.js
file and add the code below at the bottom of the file:
为了使Laravel Echo正常工作,我们需要打开./resources/assets/js/bootstrap.js
文件,并在文件底部添加以下代码:
import Echo from 'laravel-echo'window.Pusher = require('pusher-js');window.Echo = new Echo({ broadcaster: 'pusher', key: 'PUSHER_KEY', encrypted: true, cluster: 'PUSHER_CLUSTER'});
You should replace PUSHER_KEY
and PUSHER_CLUSTER
with the key and cluster for your Pusher application.
您应该用Pusher应用程序的密钥和群集替换PUSHER_KEY
和PUSHER_CLUSTER
。
Now lets create our next Vue component, AddCommentModal.vue
. It is already referenced in our FeedbackCanvas.vue
Vue component.
现在,让我们创建下一个Vue组件AddCommentModal.vue
。 我们的FeedbackCanvas.vue
Vue组件已经引用了它。
Create an AddCommentModal.vue
file in the same directory as our other Vue components. In this file, paste in the code below:
在与其他Vue组件相同的目录中创建一个AddCommentModal.vue
文件。 在此文件中,粘贴以下代码:
<template> <div id="add-modal" class="modal fade" role="dialog" data-backdrop="static" data-keyboard="false"> <div class="modal-dialog"> <div class="modal-content"> <form method="post" :action="'/feedback/'+photo.url+'post'" @submit.prevent="submitFeedback()"> <div class="modal-header"> <h4 class="modal-title">Add Feedback</h4> </div> <div class="modal-body"> <textarea name="feedback" id="feedback-provided" cols="10" rows="5" class="form-control" v-model="feedback" placeholder="Enter feedback..." required minlength="2" maxlength="2000"></textarea> </div> <div class="modal-footer"> <button type="submit" class="btn btn-primary pull-right">Submit</button> <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button> </div> </form> </div> </div> </div></template><script>export default { props: ['image'], data() { return { photo: this.image, feedback: null } }, methods: { submitFeedback: function () { let vm = this let modal = $('#add-modal') let position = modal.data("comment-position") // Create url and payload let url = `/feedback/${this.photo.url}/comment`; let payload = {comment: this.feedback, left: position.left, top: position.top} axios.post(url, payload).then(response => { this.feedback = null modal.modal('hide') vm.photo.comments[modal.data('comment-index')] = response.data $(document).ready(() => $('[data-toggle="popover"]').popover()) }) } }}</script>
In the template
section, we have defined a typical Bootstrap modal. In the modal form, we have attached a call to submitFeedback()
which is triggered when the form is submitted.
在template
部分,我们定义了典型的Bootstrap模式。 在模式表单中,我们已附加了对submitFeedback()
的调用,该调用在表单提交时触发。
In the script
section, we have defined the submitFeedback()
method in the methods
property of the Vue component. This function simply sends a comment to the backend for storage. If there is a favorable response from the API, the Bootstrap modal is hidden and the comment is appended to the image.comments
array. The Bootstrap popover is then reloaded so it picks up the changes.
在script
部分中,我们在Vue组件的methods
属性中定义了submitFeedback()
方法。 此功能只是将注释发送到后端进行存储。 如果API响应良好,则会隐藏Bootstrap模式,并将注释附加到image.comments
数组。 然后会重新加载Bootstrap弹出窗口,以便拾取更改。
With that final change, we have defined all our Vue components. Open your terminal and run the command below to build your JS and CSS assets:
经过最后的更改,我们定义了所有Vue组件。 打开终端并运行以下命令来构建JS和CSS资产:
$ npm run dev
Great! Now let’s build the backend.
大! 现在让我们构建后端。
为我们的原型反馈应用程序创建端点 (Creating the Endpoints for our prototype feedback application)
In your terminal, enter the command below:
在您的终端中,输入以下命令:
$ php artisan make:event FeedbackAdded
This will create an event class called FeedbackAdded
. We will use this file to trigger events to Pusher when we add some feedback.This will make feedback appear in realtime to anyone looking at the image.
这将创建一个名为FeedbackAdded
的事件类。 添加一些反馈后,我们将使用此文件触发事件给Pusher,这将使反馈实时显示给任何查看图像的人。
Open the PhotoController
class and replace the contents with the code below:
打开PhotoController
类,然后将内容替换为以下代码:
<?phpnamespace App\Http\Controllers;use App\Events\FeedbackAdded;use App\{Photo, PhotoComment};class PhotoController extends Controller{ public function show($url) { $photo = Photo::whereUrl($url)->firstOrFail(); return view('image', compact('photo')); } public function comment(string $url) { $photo = Photo::whereUrl($url)->firstOrFail(); $data = request()->validate([ "comment" => "required|between:2,2000", "left" => "required|numeric|between:0,100", "top" => "required|numeric|between:0,100", ]); $comment = $photo->comments()->save(new PhotoComment($data)); event(new FeedbackAdded($photo->id, $comment->toArray())); return response()->json($comment); } public function upload() { request()->validate(['file' => 'required|image']); $gibberish = md5(str_random().time()); $imgName = "{$gibberish}.".request('file')->getClientOriginalExtension(); request('file')->move(public_path('storage'), $imgName); $photo = Photo::create(['image' => $imgName, 'url' => $gibberish]); return response()->json($photo->toArray()); }}
In the above, we have a show
method which shows an image so people can leave feedback on it. Next, there is the comment
method that saves a new comment on an image. The final method is the upload
method that simply uploads an image to the server and saves it to the database.
在上面,我们有一个show
方法来显示图像,以便人们可以在其上留下反馈。 接下来,有一个comment
方法,可以在图像上保存新的注释。 最后一种方法是上upload
方法,该方法只是将图像upload
服务器并将其保存到数据库。
Let us create the view for the show
method. Create a new file in the ./resources/views
directory called image.blade.php
. In this file, paste the code below:
让我们为show
方法创建视图。 在./resources/views
目录中创建一个名为image.blade.php
的新文件。 在此文件中,粘贴以下代码:
<!doctype html><html lang="{{ app()->getLocale() }}"><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" content="{{csrf_token()}}"> <title>Laravel</title> <link href="https://fonts.googleapis.com/css?family=Roboto:400,600" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="{{ asset('css/app.css') }}"></head><body> <div id="app"> <feedback :photo='@json($photo)'></feedback> </div> <script src="{{asset('js/app.js')}}"></script></body></html>
In the above, the only thing that stands out is the feedback
tag. It is basically in reference to the feedback Vue component we built earlier in the article. Every other thing is just basic Blade and HTML.
在上面,唯一引人注目的是feedback
标签。 它基本上是参考我们在本文前面构建的反馈Vue组件。 其他所有东西只是基本的Blade和HTML。
Now that we have created the view, we need to add the directory for uploads defined in the upload
method. In your terminal, run the command below:
现在,我们已经创建了视图,我们需要添加上upload
方法中定义的upload
目录。 在您的终端中,运行以下命令:
$ php artisan storage:link
This command will create a symlink from the ./storage
directory to the ./public/storage
directory. If you look in the ./public
directory you should see the symlink.
此命令将创建从./storage
目录到./public/storage
目录的符号链接。 如果查看./public
目录,则应该看到符号链接。
Now that we have created the backend to support our web application, we need to add Pusher to the backend so that the comments made are broadcasted and can be picked up by other people browsing the image.
现在,我们已经创建了支持Web应用程序的后端,我们需要将Pusher添加到后端,以便广播所发表的评论,并且其他浏览该图像的人也可以将其提取。
使用Pusher将实时功能添加到原型反馈应用程序中 (Adding realtime functionality to the prototype feedback app using Pusher)
Open your terminal and enter the command below to install the Pusher PHP SDK:
打开终端,然后在下面输入命令以安装Pusher PHP SDK :
$ composer require pusher/pusher-php-server "~3.0"
Open the .env
file and scroll to the bottom and configure the Pusher keys as seen below:
打开.env
文件并滚动到底部,然后按如下所示配置Pusher键:
PUSHER_APP_ID="PUSHER_ID"PUSHER_APP_KEY="PUSHER_KEY"PUSHER_APP_SECRET="PUSHER_SECRET"
Also in the same file, look for the BROADCAST_DRIVER
and change it from log
to pusher
.
同样在同一文件中,查找BROADCAST_DRIVER
并将其从log
更改为pusher
。
Next, open the ./config/broadcasting.php
and scroll to the pusher
key. Replace the options
key of that configuration with the code below:
接下来,打开./config/broadcasting.php
并滚动到pusher
键。 用以下代码替换该配置的options
键:
// ...'options' => [ 'cluster' => 'PUSHER_CLUSTER', 'encrypted' => true], // ...
? Remember to replace theP
USHER_ID,
PUSHER_KEY,
PUSHER_SECRET
andPUSHER_CLUSTER
with the values from your Pusher application.? [R 请记得替换求解P
USHER_ID,
PUSHER_KEY,
PUSHER_SECRET
一个NDPUSHER_CLUSTER
从推应用瓦特i个值。
Now, open the FeedbackAdded
class and replace the contents with the code below:
现在,打开FeedbackAdded
类,并将内容替换为以下代码:
<?phpnamespace App\Events;use Illuminate\Broadcasting\Channel;use Illuminate\Queue\SerializesModels;use Illuminate\Foundation\Events\Dispatchable;use Illuminate\Broadcasting\InteractsWithSockets;use Illuminate\Contracts\Broadcasting\ShouldBroadcast;class FeedbackAdded implements ShouldBroadcast{ use Dispatchable, InteractsWithSockets, SerializesModels; public $comment; public $photo_id; public function __construct(int $photo_id, array $comment) { $this->comment = $comment; $this->photo_id = $photo_id; } public function broadcastOn() { return new Channel("feedback-{$this->photo_id}"); } public function broadcastAs() { return 'added'; }}
In the class above, we define the comment
object and the photo_id
which will be used to compose the channel name in the broadcastOn
method. We also define the broadcastAs
method, which will allow us to customize the name of the event being sent to Pusher.
在上面的类中,我们定义了comment
对象和photo_id
,它们将用于在broadcastOn
方法中组成频道名称。 我们还定义了broadcastAs
方法,这将使我们能够自定义发送给Pusher的事件的名称。
That’s all. Now, let’s run our application. In your terminal, run the code below:
就这样。 现在,让我们运行我们的应用程序。 在您的终端中,运行以下代码:
$ php artisan serve
This should start a new PHP server and you can then use that to test your application. Go to the URL given and you should see your application.
这应该启动一个新PHP服务器,然后您可以使用它来测试您的应用程序。 转到给出的URL,您应该会看到您的应用程序。
结论 (Conclusion)
In this article, we have successfully created a prototype application’s feedback feature that will allow designers to share their designs with others and receive feedback on them.
在本文中,我们成功创建了原型应用程序的反馈功能,该功能将使设计人员可以与他人共享他们的设计并接收有关他们的反馈。
If you have questions or feedback, please leave them as a comment below. The source code to the application is available on GitHub.
如果您有任何疑问或反馈,请在下面留下它们作为评论。 该应用程序的源代码可在GitHub上找到 。
This post first appeared on the Pusher blog.
这篇文章首先出现在Pusher博客上 。
vue js 对象下的原型