Laravel和EmberJS的单页应用程序

在这一部分中,我们将看到Ember的工作原理,如何使用Ember Data以及如何使用它构建简单的东西。 路由器,路由,模型,模板和存储是Ember的一些概念。 我不会解释其中的每一个,因此,如果您感到困惑,请使用文档 。 与往常一样,您可以在此处下载该部分的代码。

让我们编码

请注意,在使用Ember开发时,最好下载Ember Inspector。 他们发布了带有Chrome扩展程序的Ember,现在该扩展程序也在Firefox上。

对于此示例,我们将JS的每一行都放在/public/static/app.js 。 在实际的项目中,这不是一个好主意。 这简化了我们的示例,但请问自己-您是否曾经在一个大文件中对MVC架构进行过认真的工作? 我们看到了Laravel的工作方式:控制器在一个文件夹中,每个控制器在一个文件中,配置在其自己的文件夹中,模型也在其中。 我建议您在进入适当的项目时对Ember做同样的事情。

启动Ember时要做的第一件事就是创建应用程序。 它是您使用Ember编写的所有代码的全局命名空间。 可以这样创建一个应用程序:

App = Ember.Application.create();

我建议在创建应用程序时仅通过添加一行代码来激活一些调试功能。

App = Ember.Application.create({
        LOG_TRANSITIONS: true
    });

它的作用不只是通过控制台中的URL和模板输出您的动作。 另外,我们将使用Ember Data,它是Ember的一个独立模块,可与REST很好地集成,将所有内容从存储对象转换为服务器上的请求。 默认情况下,Ember Data使用剩余适配器。 您也可以使用夹具适配器进行测试和本地开发。 基本上,Ember Data是服务器(Rest API)和具有存储对象的本地存储之间的桥梁。

如前所述,我们的API使用命名空间。 Ember的数据带有一个Rest适配器,该适配器接受一个名称空间,这个前缀就像我们在Laravel Route组上看到的一样。 让我们传入名称空间作为参数。

App.ApplicationAdapter = DS.RESTAdapter.extend({
        namespace: 'api/v1'
    });

适配器现在通过example.com/api/v1/请求所有数据。

将App Store与适配器链接起来,就可以开始开发了。

App.Store = DS.Store.extend({
        adapter: 'App.ApplicationAdapter'
    });

Ember的主要概念之一是URL。 一切都围绕着这个想法。 路由器使URL和模板保持同步。 在路由器内部,您可以定义资源并将该资源映射到特定的URL。 在此示例中,我们将仅使用照片资源和用户资源。 随时添加类别资源,并与Ember建立一对多关系。 不要忘记,我们之前曾与Laravel建立了一些关系(一对多和属于),但是我们并没有使用它们。 在Laravel中使用一对多关系很容易,但是我不想让您不知所措。 如果对评论产生了足够的兴趣,我们将在后续帖子中将其与分页一起添加到我们的应用中。

路由器是应定义所有路由的地方。 在这里,我们用它们的URL定义了两个资源。 URL在这里是可选的。 :photo_id是一个参数。 假设我们导航到example.com/photo/2 。 会发生什么? 我们有一个资源可以将我们的请求传递给模型或控制器,并在那里从商店中获取一些数据。 如果商店找不到,它将在服务器上查找。 :photo_id可用于检索此数据。 在这种情况下,它将查找example.com/api/v1/photos/2 。 您会看到照片是复数的。 Ember本身会寻找资源的复数形式。

App.Router.map(function() {
        this.resource('photo', {path: "/photo/:photo_id"});
        this.resource('user', {path: "/user/:user_id"});
    });

路由以资源的首字母大写开头,并且应位于App命名空间中。 另外,在资源名称后添加“ Route”一词。 因此,对于照片资源,路线应如下所示: App.PhotoRoute

它还应该扩展Route对象。

App.PhotoRoute = Ember.Route.extend({});

路由对象可以具有用于不同事物的不同钩子。 这些挂钩中的两个用于定义该资源的控制器名称和定义模型。 让我们坚持使用模型。

App.PhotoRoute = Ember.Route.extend({
        model: function(params){
            return this.store.find('photo', params.photo_id);
        }
    });

在内部,我们指定了模型挂钩并传递了一个参数。 该参数在哪里? 图片资源的网址带有参数: /photo/:photo_idphoto_id存储在params并且可以在函数内部使用。 不要忘记,每个资源和每条路线都可以访问商店。 Store对象将所有信息保存在其中,并使用Local Storage以获得更好的性能。 这样,它减少了服务器上的请求数量。 这就是为什么使用Ember开发可以加快您的应用程序的速度-最终,用户会更快乐。

通过使用store.find('resource')您可以从store对象中检索该资源的所有数据。 您也只能检索一行。 例如,如果您只想接收具有给定id的照片,请使用store对象并找到具有给定id的照片资源作为第二个参数。

return this.store.find('photo', params.photo_id);

灰烬在example.com/api/v1/photo_id搜索数据。 默认情况下,Ember通过查找ID来处理数据。 如果您为此资源插入了一些关系,则还可以检索与其关联的数据。 这就是路线的所有代码,每种情况都非常相似且简单明了:

App.IndexRoute = Ember.Route.extend({
        model: function(){
            return this.store.find('photo');
        }
    });
    
    App.PhotoRoute = Ember.Route.extend({
        model: function(params){
            return this.store.find('photo', params.photo_id);
        }
    });
    
    App.UserRoute = Ember.Route.extend({
        model: function(params){
            return this.store.find('user', params.user_id);
        }
    });

快速说明:IndexRoute是默认路由,与根URL链接。 从根本上讲,我的意思是example.com/ URL。 还有其他默认路由,例如ApplicationRoute在应用程序启动时执行。

模型对象

在Ember的模型对象中,您可以指定数据及其资源类型。 Ember的一个不错的功能是,当资源的值更改并且另一个值取决于更改后的值时,它会通过观察者的魔法自动更新。 模型应以大写字母开头,并应扩展模型对象。

App.Photo = DS.Model.extend({});

在该对象内,您应该指定所有字段和其他依赖于这些核心值的值。 您也可以在模型内部添加“关系”。

照片模型应如下所示:

var attr = DS.attr;             // This cuts my writting. Inside the model i use attr instead of DS.attr
    
    App.Photo = DS.Model.extend({
        user_id: attr("number"),    // The expected value is a number
        url: attr("string"),        // The expected value is a string
        title: attr("string"),
        description: attr("string"),
        category: attr("number"),
    
        fullUrl: function(){        // Another value that depends on core values.
            return "/files/" + this.get("url");
        }.property('url'),
    
        backgroundImage: function(){// This depends on another value but not on core ones
            return 'background: url("' + this.get("fullUrl") + '") no-repeat; ';
        }.property('fullUrl')
    
    });

使用attrDS.attr ),您可以指定如何希望这些数据到达。 例如,我们希望user_id值是一个数字。 这样,我们可以免受外部数据的攻击。

用户模型相似。 请记住,Ember Data将在/api/v1/users寻找它。 命名约定有些棘手。 例如,如果您请求一个名为user的资源,Ember Data将查找example.com/prefix/users ;如果您请求一个特定的资源,则它将请求example.com/prefix/users/user_id 。 了解Laravel如何公开数据以及Ember如何希望其数据可以使您免于头痛。

App.User = DS.Model.extend({
        name: attr("string"),
        lastname: attr("string"),
        username: attr("string"),
    
        fullname: function(){
            return this.get('name') + " " + this.get('lastname');
        }.property("name", "lastname")
    });

观看次数

在跳入模板之前,建议您使用Ember Inspector查看应用程序的状态。 在此可以找到路线,视图和控制器。 您还可以找到控制器和路由之间的关系。 花一些时间与Inspector环顾一下,稍后在您开发自己的Ember应用程序时会提供很大的帮助。

您还记得我们在第三部分中编写的第一个模板吗? 那就是应用程序模板。 在浏览器中访问example.com时,将呈现该模板。

如果未在该模板内进行修改,则无法进一步开发该应用程序。 将<!-- The content will be here -->替换为<!-- The content will be here -->注释为: {{outlet}}

为什么? 我们所有的资源都嵌套在应用程序路由内。 但是,如果我查看代码,则路由器上看不到索引。 这是为什么?

默认情况下, example.com/ url分配给IndexRoute除非您已将该URL分配给另一个路由。 Ember默认情况下将应用程序置于顶层,并且所有内容都嵌套在其中。 如果您在该应用程序路由内请求一个URL,则通过使用{{outlet}}作为占位符,Ember将采用该路由的模板并将其放在该占位符内。

让我们制作另一个模板并将其用于IndexRoute 。 这将是第一页。 第一个模板是应用程序模板。 索引模板将呈现在应用程序的{{outlet}}

data-template-namedata-template-name 。 该脚本标签内的所有代码都将放置在{{outlet}}

<script type="text/x-handlebars" data-template-name="index">
        <ul class="small-block-grid-1 medium-block-grid-2 large-block-grid-3 custom-grid-ul">
            {{#each}}

                <li {{bind-attr style="backgroundImage"}}>
                    <div class="custom-grid">
                        {{#link-to 'photo' this}}<h5 class="custom-header">{{title}}</h5>{{/link-to}}
                        <span>Author: {{user_id}}</span>
                    </div>
                </li>

            {{/each}}
        </ul>
    </script>

{{#each}}就像一个循环。 如果模板的模型有一个数组,并且我们要查询所有数据,则可以使用此特殊标记。 该循环以{{#each}}开始,以{{/each}} 。 在此循环内,我们使用从循环返回的所有值。 记住,在模型内部我们返回了资源photo 。 该模型从商店中检索数据,并将其返回到模板。 看一下照片模型。 我们在此处指定了一些字段,并且这些模板模板{{#each}}循环中正在使用这些字段。

另一个特殊标签是{{#link-to}}标签。 该标签会生成指向照片路线的链接并传递参数。 this参数是该对象的id 。 在这种情况下,带照片的身份证。 同样, {{#link-to}}标签以{{/link-to}}结尾。 {{title}}不是一个特殊标记,它仅检索该对象的标题值。

让我们添加照片模板。 此模板是“照片路线”的模板。 同样,我建议查看有关如何映射以及如何完成命名的命名约定

<script type="text/x-handlebars" data-template-name="photo">
        <div style="text-align: center;">
            <h4>{{title}}</h4><br>
            <img {{bind-attr src="fullUrl" alt="title"}}><br>
            <span>Author: {{#link-to 'user' user_id}}{{author.name}}{{/link-to}}</span>
        </div>
    </script>

通过使用{{attribute-here}}标签,所选属性将在此标签内生成。 我们在<img>标签中使用了它。 将标记内的{{title}}用作属性会导致问题。 把手和Ember在DOM内生成一些额外的对象。 为了解决这个问题,我们改用{{bind-attr}} 。 当我们链接到用户路线时,我们传递一个参数: user_id 。 通过单击链接,URL将使用example.com/user/the_id进行更新。 但是我们还没有用户模板。 让我们创建一个。

<script type="text/x-handlebars" data-template-name="user">
        <h2>Hello: {{fullname}} </h2>
    </script>

这仅显示全名。 fullname是我们的财产App.User扩展DS.Model

在将所有内容打包之前,我对它的外观进行了gif处理:

enter image description here

包起来

如您所见,这尚未完成。 仍然需要大量工作。 继续尝试它,从中学习并改变它。 完整的项目将托管在我的Github帐户上 ,并将经常更新。 欢迎任何贡献,我很乐意共同努力。

在本系列中,我们学到了很多东西-我也学到了很多东西。 我们了解了如何使用云,了解了云的优缺点。 我们了解了如何在两种环境中开发应用程序,以及如何为不同的环境配置Laravel。 我们看到了如何通过与Ember保持在应用程序的同一页面上来使用Laravel构建REST API。 希望大家都和我一样开心。

你怎么看? 您想在Heroku,Laravel或Ember上看到更多吗? 在下面发表评论,总是很高兴听到读者的反馈!

From: https://www.sitepoint.com/single-page-app-laravel-emberjs/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值