在Emberjs中生成 component

Emberjs 中component 的创建以及本地 使用 ember-cli-mirage 来mock数据

在实际的项目中,我们总会重复写一些代码来实现一些相同的功能,比如说购物车列表内的每一项,比如说租房列表中的每一项。它们的样式都一样,我们也不可能为每一项复制一遍。这个时候我们就可以使用 handlebarseach as 以及 emberjscomponent来写出简洁的代码。而在 emberjs 中我们还可以使用 ember-cli-mirage来mock本地数据,从而可以在后期更快地与后端对接数据。

模拟场景

我们以 链家 再售的二手房列表为例:
11-14-14-03.png
分析:
可以看到每一个 房产(条目) 都具有相同的结构,分为左侧的展示图片,右侧的标题以及其他具体信息等。

具体操作

使用emberjs 框架开始创建一个组件,并mock本地数据(使用在 EmberGuide 教程中的项目)。

创建基本组件:

ember g component lj-ershoufang

可以看到 ember-cli 帮我们生成了两个文件,一个是主管组件展示的template.hbs,另一个是主管组件逻辑的component.js1

组件的数据传递

在一个简单的组件中:

	{{!-- component-train-passing-properties/template.hbs --}}
	<h2>{{title}}</h2>

我们可以在 component.js 中为 title 变量赋值,在 handlebars 文件中将会展示出来:

	//	component-train-passing-properties/component.js
	//	...
	this.set('title','welcome to use emberjs');

而在调用组件页面我们将会看到这句话。

passing-properties
但是在实际项目中,我们基本上都是从后端接受数据再通过路由中的handlebars 文件调用组件,将数据传递进去,再进行相应的展示:

	{{!-- train/template.hbs --}}
	{{component-train-passing-properties title="Welcome to use component!"}}

这个时候,在组件的调用页面,我们就可以看到

usecomponent
展示在我们面前了。

使用 flex 布局 书写相关代码。

要注意 flex 布局的兼容性问题。(待补充)

自定义组件属性:

  1. 修改包裹体的标签:
    默认的 组件 外部的包裹元素为div,我们可以通过使用 tagName: 'li' 这种语法来修改包裹体的标签;
  2. 向组件添加 类 名:
    有以下几种方法:
    - 在定义的时候通过属性添加: classNames: ['header-title']
    - 在调用的时候通过属性传递: {{component-train-passing-properties class='passing-properties-container'}};
    - 绑定某一属性,动态添加类:
	//	component-train-passing-properties/component.js
	classNameBindings: ["showBg:show-background"]
	而后在对应的 `styles.scss`文件内写上样式,这里是添加背景色。
	在调用端:
{{!-- train/template.hbs --}}
<section local-class="defined-class">
	{{component-train-passing-properties title=title showBg=true}}
	{{component-train-passing-properties title=title showBg=false}}
</section>

可以看到:
动态绑定类名
如果classNameBindings 绑定的属性的值是一个字符串,那字符串将直接传递入组件的类中。

模拟相关数据。

详细代码

在新创建的展示路由中howGenerateComponent中,添加展示区域:

<h1>how to Generate a component</h1>
<section  local-class="ershoufang-list-container">
	<ul>
		{{#each  model  as |item|}}
			{{lj-ershoufang  data=item}}
		{{/each}}
	</ul>
</section> 

而在路由的route.js文件中,我们使用最原始的生成数据方式:

import Route from  "@ember/routing/route";

export  default Route.extend({
	model() {
		return [{
			img:  "https://image1.ljcdn.com/110000-inspection/test-5cca6d6b-1419-46aa-9938-b03dcb90602b.jpeg.296x216.jpg",
			title:  "南北通透两居室 2010年建成 板楼有电梯",
			address:  "鸿业兴园二区",
			houseInfo: ["鸿业兴园二区 ", "2室1厅", "88.14平米", "南 北", "简装"],
			positionInfo: ["高楼层(共18层)", "2009年建板塔结合", "玉泉营"],
			followInfo: ["1135人关注", "33次带看"],
			tag: ["房本满五年", "随时看房"],
			totalPrice:  460,
			perPrice:  52190
		},
		{
			img:  "https://image1.ljcdn.com/110000-inspection/test-dabcf77d-5c2c-4601-b528-e557a12deff9.jpeg.296x216.jpg",
			title:  "靠近地铁8号线,小区中间位置,中间楼层,已经满五年",
			address:  "和谐家园一区 ",
			houseInfo: ["和谐家园一区 ", "3室2厅", "124.08平米", "南 北", "简装", "无电梯"],
			positionInfo: ["低楼层(共6层)", "2006年建板楼", "回龙观"],
			followInfo: ["1630人关注", "42次带看"],
			tag: ["近地铁", "房本满五年", "随时看房"],
			totalPrice:  540,
			perPrice:  43521
		}
	];
}
});

样式文件就不写了。
这时候可以看到我们使用了 each as 的 handlebars 语法,遍历的数组是 model hook 中 return 出来数组。将遍历出来的数组的每一项传入了 lj-ershoufang 这个组件中。
在组件中我们可以看到:

<img local-class="ershoufang-info info-img" src={{data.img}} alt="data.title">  
<div local-class="ershoufang-info info-detail">
  <p local-class="detail-item title">{{data.title}}</p>  
  <p local-class="detail-item house-info">{{#each data.houseInfo as |hinfo|}} {{hinfo}}<span local-class="divide">/</span> {{/each}}</p>  
  <p local-class="detail-item position-info">{{#each data.positionInfo as |pinfo|}} {{pinfo}} <span local-class="divide">/</span> {{/each}}</p>  
  <p local-class="detail-item follow-info">{{#each data.followInfo as |finfo|}} {{finfo}} <span local-class="divide">/</span> {{/each}}</p>  
  <p local-class="detail-item tag-info">{{#each data.tag as |tag|}} <span> {{tag}} </span> {{/each}}</p>  
  <div local-class="price-info">
    <p local-class="total-price"><span>{{data.totalPrice}}</span> </p>  
    <p local-class="per-price">  <span>单价</span> {{data.perPrice}} <span>/平米</span>  </p>  
  </div>
</div>

可以看到,具体使用传来的数据的时候就使用data.img之类的方式。也就是 javascript 中从对象中取值的方式。
component.js也支持一些属性来让我们自定义一些组件的样式等:

import Component from  "@ember/component";

export  default Component.extend({
	localClassNames:  "lj-ershoufang",
	classNames: ["ershoufang-list"],
	tagName:  "li"
});

tagName是自定义组件最外层的包裹体的tag的名称;classNames 是向组件添加类名;localClassNames 是向组件添加 css-modules 的类。
现在可见的页面为:
11-14-17-00.png

使用 ember-cli-mirage虚拟数据

在实际的生产中前端总是在向后端请求数据,当数据返回后,前端将接收到的数据展示出来:

//	mirage/config.js
export  default  function () {
this.namespace =  "/api";
this.get("/ershoufangs", function () {
	return {
		data: [
			{
				type:  "ershoufang",
				id:  "ershoufang01",
				attributes: {
					img:  "https://image1.ljcdn.com/110000-inspection/test-5cca6d6b-1419-46aa-9938-b03dcb90602b.jpeg.296x216.jpg",
					title:  "南北通透两居室 2010年建成 板楼有电梯",
					address:  "鸿业兴园二区",
					houseinfo: ["鸿业兴园二区 ", "2室1厅", "88.14平米", "南 北", "简装"],
					positioninfo: ["高楼层(共18层)", "2009年建板塔结合", "玉泉营"],
					followinfo: ["1135人关注", "33次带看"],
					tag: ["房本满五年", "随时看房"],
					totalprice:  460,
					perprice:  52190
				}
			},
			{
				type:  "ershoufang",
				id:  "ershoufang02",
				attributes: {
					img:  "https://image1.ljcdn.com/110000-inspection/test-dabcf77d-5c2c-4601-b528-e557a12deff9.jpeg.296x216.jpg",
					title:  "靠近地铁8号线,小区中间位置,中间楼层,已经满五年",
					address:  "和谐家园一区 ",
					houseinfo: ["和谐家园一区 ", "3室2厅", "124.08平米", "南 北", "简装", "无电梯"],
					positioninfo: ["低楼层(共6层)", "2006年建板楼", "回龙观"],
					followinfo: ["1630人关注", "42次带看"],
					tag: ["近地铁", "房本满五年", "随时看房"],
					totalprice:  540,
					perprice:  43521
				}
			}
		]
	};
});
}

可以看到数据放在了ershoufangs 的请求链接下,数据内的type就代表着 emberjs 中的 model 实例,生成 model 实例的方式为:

ember g model ershoufang

在生成的 ershoufang/model.js 文件下,

import DS from  "ember-data";

export  default  DS.Model.extend({
	img:  DS.attr("string"),
	title:  DS.attr("string"),
	address:  DS.attr("string"),
	houseinfo:  DS.attr(),
	positioninfo:  DS.attr(),
	followinfo:  DS.attr(),
	tag:  DS.attr(),
	totalprice:  DS.attr("number"),
	perprice:  DS.attr("number")
});

而在我们路由下的 route.js 将改为:

import Route from  "@ember/routing/route";

export  default Route.extend({
	model() {
		return  this.store.findAll("ershoufang");
	}
});

数据就可以正常的显示了。

Written by Frank Wang.

有问题可以下方评论,或发邮件至 法研鲁迅 .


  1. 在使用原生的目录结构时,生成的文件名称可能有所不同;另外 组件的名称也必须有中划线。 ↩︎

猜你喜欢

转载自blog.csdn.net/peng_9/article/details/84069961