创建简单组件

优质
小牛编辑
120浏览
2023-12-01

当用户查看我们的租借列表时,他们可能希望有一些交互式选项来帮助他们作出决定。让我们添加切换每个租赁图像大小的功能。为此,我们将使用一个组件。
我们生成一个rental-listing组件来管理我们每个租赁的行为。每个组件名称中都要有一个破折号,来避免与可能的HTML元素冲突,因此命名rental-listing允许,受但命名rental不允许。
生成一个组件:

$ ember g component rental-listing
installing component
  create app/components/rental-listing.js
  create app/templates/components/rental-listing.hbs
installing component-test
  create tests/integration/components/rental-listing-test.js

组件由两部分组成:

  • 一个定义它外观的模板(app/templates/components/rental-listing.hbs) 一个JavaScript源文件(app/components/rental-listing.js),用于定义它的行为方式。

我们的新rental-listing组件将管理用户看到的样子和与租赁交互。首先,我们将租赁显示详细信息从rentals.hbs模板中移到rental-listing.hbs(app/templates/components/rental-listing.hbs)并添加图像字段:

<article class="listing">
  <img src="{ { rental.image } }" alt="">
  <h3>{ { rental.title } }</h3>
  <div class="detail owner">
    <span>Owner:</span> { { rental.owner } }
  </div>
  <div class="detail type">
    <span>Type:</span> { { rental.propertyType } }
  </div>
  <div class="detail location">
    <span>Location:</span> { { rental.city } }
  </div>
  <div class="detail bedrooms">
    <span>Number of bedrooms:</span> { { rental.bedrooms } }
  </div>
</article>

对比看看原来的app/templates/rentals.hbs,会发现基本上是把each model循环中内容定义的内容移到了组件模板中。那么现在修改rentals.hbs,在each model循环中引用新建立的组件:

<div class="jumbo">
  <div class="right tomster"></div>
  <h2>Welcome!</h2>
  <p>
    We hope you find exactly what you're looking for in a place to stay.
  </p>
  { { #link-to 'about' class="button" } }
    About Us
  { { /link-to } }
</div>

{ { #each model as |rentalUnit| } }
  { { rental-listing rental=rentalUnit } }
{ { /each } }

这里我们调用名称为rental-listing的组件,并将其rentalUnit赋予组件的rental属性。
ember s运行超级租赁应用,通过浏览器访问 http://c7302.ambari.apache.org:4200

隐藏和显示图片

现在添加按用户请求显示图片的功能。
我们使用{ { if } }助手检查isWide是否为true来决定是否显示租赁图像。我们还将添加一些文本来指示可以单击图像,并使用一个锚点元素包含它,给它一个image类名,以便我们的测试可以找到它。
修改组件模板文件app/templates/components/rental-listing.hbs

<article class="listing">
  <a class="image { { if isWide "wide" } }">
    <img src="{ { rental.image } }" alt="">
    <small>View Larger</small>
  </a>
  <h3>{ { rental.title } }</h3>
(下略)

isWide的值来自于组件的JavaScript文件(app/components/rental-listing.js)。由于我们希望以小图像开始,因此把属性设置为false

import Ember from 'ember';

export default Ember.Component.extend({
  isWide: false
});

为了让用户可以放大图像,我们添加一个动作(action)来切换isWide的值,我们定义这个动作叫toggleImageSize。组件模板app/templates/components/rental-listing.hbs修改为:

<article class="listing">
  <a { { action 'toggleImageSize' } } class="image { { if isWide "wide" } }">
    <img src="{ { rental.image } }" alt="">
    <small>View Larger</small>
  </a>
...

单击锚点元素将发送动作到组件。然后,Ember将进入actions散列并调用toggleImageSize函数。
动作散列是一个包含多个函数的组件对象。当用户与UI进行交互(例如点击)时,将调用这些函数。

我们创建toggleImageSize函数并切换组件上的isWide属性(app/components/rental-listing.js):

import Ember from 'ember';

export default Ember.Component.extend({
  isWide: false,
  actions: {
    toggleImageSize() {
      this.toggleProperty('isWide');
    }
  }
});

现在,当我们在浏览器中点击图形或View Larger链接时,会看到大图像显示。当我们再次点击放大的图像,我们看到它变小。

集成测试

Ember组件通常通过组件集成测试进行测试。组件集成测试在Ember渲染引擎的上下文中验证组件的行为。当在集成测试中运行时,组件将经历其常规渲染生命周期,访问依赖对象,并且通过Ember解析器加载。

我们的组件集成测试将测试两种不同的行为:

  • 组件应显示有关租赁的详细信息
  • 该组件应该在点击时切换isWide,以及扩展和缩小租赁照片。

对于测试,我们将会向组件传递具有租赁模型所有属性的假对象。我们给变量命名为rental,在每个测试中,我们用this对象,将rental设置到本地范围(scope)。渲染模板可以访问本地范围内的值。 最终的tests/integration/components/rental-listing-test.js:

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';

let rental = Ember.Object.create({
  image: 'fake.png',
  title: 'test-title',
  owner: 'test-owner',
  propertyType: 'test-type',
  city: 'test-city',
  bedrooms: 3
});

moduleForComponent('rental-listing', 'Integration | Component | rental listing', {
  integration: true
});

test('should display rental details', function(assert) {
  this.set('rentalObj', rental);
  this.render(hbs`{ { rental-listing rental=rentalObj } }`);
  assert.equal(this.$('.listing h3').text(), 'test-title', 'Title: test-title');
  assert.equal(this.$('.listing .owner').text().trim(), 'Owner: test-owner', 'Owner: test-owner')
});

test('should toggle wide class on click', function(assert) {
  this.set('rentalObj', rental);
  this.render(hbs`{ { rental-listing rental=rentalObj } }`);
  assert.equal(this.$('.image.wide').length, 0, 'initially rendered small');
  Ember.run(() => document.querySelector('.image').click());
  assert.equal(this.$('.image.wide').length, 1, 'rendered wide after click');
  Ember.run(() => document.querySelector('.image').click());
  assert.equal(this.$('.image.wide').length, 0, 'rendered small after second click');
});

运行集成测试ember t -s,浏览器访问7357端口,显示为7个测试3个失败。