博客
电影
宝箱
友链
关于
<
《鼠疫》读后感,人人携带鼠疫
《呼啸山庄》读后感,偏激的爱情
>
ember入门教程
作者:
Cifer
类别: 技术
时间:2018-08-17 09:40:41
字数:6666
版权所有,未经允许,请勿转载,谢谢合作~
### 快速开始 Ember是一个工程化前端开源框架,集构建、路由、模板引擎,数据持久等一身。当前热度不如React和Vue,github star约19K,国外使用者居多,如NASA官网便是用这个框架。Ember最好的教程必然是其官网,不过本文是对其简化的介绍。 在此讲解<a href="http://www.boatsky.com/blog/44.html">ember入门教程</a>之前,先推荐一个JS包管理工具yarn,比npm快得多,版本也相对统一,<a href="https://yarnpkg.com/zh-Hans/" target="_blank" rel="nofollow">yarn官网</a>,下以mac为例。 安装ember ```javascript yarn install -g ember-cli ``` 一键生成ember应用study ```javascript ember new study ``` 以下任一方法启动应用,推荐后者,默认使用4200端口(如果因为权限问题跑失败,推荐相关文件修改dwr权限,不太推荐使用sudo) ```javascript ember server yarn run start ``` 如需更改,可修改/添加 study/.ember-cli ```javascript { "port": 4200 } ``` 如果端口被占用,找到pid并kill ``` lsof -i:4200 kill -9 pid ``` 一般都可成功,如果失败了,可能是之前使用sudo的原因,试着用sudo再试一次,或者删除node_modules所有内容重新: ``` yarn install --ignore-engines ``` 项目默认有以下模块 routes 路由层 models 模型层 controllers 业务逻辑层 components 组件,一般与Templates同时使用 templates 页面模板,分为路由的模板与组件模板,组件模板放置在 templates/components,文件后缀是hbs,因为使用了xxx styles 样式,分路由样式与组件样式,组件样式放置在 styles/components 一般来说,route,model,controller,template,style五者文件名相同 同时可附加以下非必须模块 services 业务抽象服务,比如登录后的用户信息管理,每当其他模块有需要时进行注入,Ember.inject.service('serviceName'),在内存层管理通用信息 helpers 函数库,除在js的模块中使用,还可以在hbs直接使用,不过一次只能使用一次 mixins 父函数集,多个业务层的父业务逻辑,可使用ember extend它 举例,分别生成route,component,controller,model,这种方式可以更快更精确的生成当前版本的架子: ``` ember g route order/index ember g component order/order-list ember g controller order/index ember g model order ``` ##### route app/router.js 路由入口: ``` import EmberRouter from '@ember/routing/router'; import config from './config/environment'; const Router = EmberRouter.extend({ location: config.locationType, rootURL: config.rootURL }); Router.map(function() { this.route('order', function() { this.route('index', {path: '/'}), this.route('detail', {path: '/:order_id'}); }); }); export default Router; ``` index,detail是order的子路由,path是该路由对应的url,默认就是路由名,比如index的路由是 /order/index或order app/routers/order/index.js 单个路由: ``` import Route from '@ember/routing/route'; export default Route.extend({ queryParams: { page: { refreshModel: true }, size: { refreshModel: true } }, model(params) { console.log(params); return { orders: [{id: 1,name: 'computer', price: 6000,},{id: 2,name: 'food', price: 100,}], user: {name: 'Odysseus'} }; }, }); ``` page与size是分页参数,return这里模拟返回数据 ##### controller app/controllers/order/index.js 单个router对应业务,非必须: ```javascript import Controller from '@ember/controller'; export default Controller.extend({ init: function() { this._super(); }, actions: { } }); ``` actions里是view中想要触发的事件 ##### model app/models/order.js 模型,与api的数据一一对应: ```javascript import DS from 'ember-data'; export default DS.Model.extend({ id: DS.attr('number'), name: DS.attr('string'), price: DS.attr('number'), }); ``` 模型之间可以有关联关系,DS.belongsTo('modelName'),DS.hasMany ('modelName')。如 A belongsTo B,B belongsTo A,A一对一B。 A belongsTo B,B hasMany A,B一对多A。 A hasMany B,B hasMany A,A多对多B。 ##### adapters model的一个功能,特别拿出来说明一下,正常来说每个model会对应一个同名api,如果不同名,则需配置,如果全站api前缀相同,直接配在app/adapters/application.js即可,否则可每个model配置: ```javascript import DS from 'ember-data'; export default DS.JSONAPIAdapter.extend({ namespace: 'api/v1' }); ``` ##### template app/templates/order/index.hbs 路由对应的view: ```html <h2>{{model.user.name}} order list</h2> {{order/order-list orders=model.orders}} {{outlet}} ``` {{outlet}}表示子路对应页面由渲染的位置, template使用的是Handlebars模板引擎,如想了解更多信息,可以查看: <a href="http://www.boatsky.com/blog/18.html" target="_blank">Ember之Handlebars模板引擎</a> ##### component 组件order-list: app/components/order/order-list.js ```javascript import Component from '@ember/component'; export default Component.extend({ actions: { jumpDetail(id) { alert(id); } } }); ``` app/templates/components/order/order-list.hbs ```html <ul> {{#each orders as |order|}} <li {{action "jumpDetail" order.id}}>{{order.name}},{{order.price}}</li> {{/each}} </ul> {{yield}} ``` {{yield}}表示,组件向调用该组件的地方传值。为了方便理解,这里改造order/order-list app/templates/order/index.hbs 调用处修改: ```html <h2>{{model.user.name}} order list</h2> {{#order/order-list orders=model.orders user=model.user as |postUser postOrders|}} {{postOrders.name}}: {{#each postUser as |order|}} <li {{action "jumpDetail" order.id}}>{{order.name}}-{{order.price}}</li> {{/each}} {{/order/order-list}} {{order/order-list orders=model.orders}} {{outlet}} ``` 上面两种不同的方式使用order/order-list,前者把orders与user传至组件中,再从组件中得到传回来的参数postUser postOrders,然后在本页面组件标签里渲染,此时jumpDetail不再是组件的事件,而是controller/order/index.js的事件了。后者只传参数给组件,组件渲染后自动转回渲染后的页面。 app/templates/components/order/order-list.hbs 修改 ```html {{#if hasBlock}} {{yield orders user}} {{else}} {{#each orders as |order|}} <li {{action "jumpDetail" order.id}}>{{order.name}},{{order.price}}</li> {{/each}} {{/if}} ``` 如果外部调用组件时有自定义的模板,则传回数据(本处是原样传回数据,如业务有需要,可在conponent中修改后传回)。否则用本组件的模板。 ### computed 与 observer computed: <a href="https://guides.emberjs.com/release/object-model/computed-properties/" target="_blank" rel="nofollow">https://guides.emberjs.com/release/object-model/computed-properties/</a> observer: <a href="https://guides.emberjs.com/release/object-model/observers/" target="_blank" rel="nofollow">https://guides.emberjs.com/release/object-model/observers/</a> 官网讲的很清楚,这里进一步说明,我这把官网dome修改一下: ```javascript import EmberObject, { computed, observer } from '@ember/object'; let Person = EmberObject.extend({ fullName: computed('firstName', 'lastName', function() { console.log('fullName computed'); return this.get('firstName') + ' ' + this.get('lastName'); }), fullNameObserver: observer('firstName', 'lastName', function() { console.log('fullName Observer'); return this.get('firstName') + ' ' + this.get('lastName'); }), }); let person = Person.create(); person.set('firstName', '西法'); setTimeout(function() { person.set('lastName', '太空船博客'); }, 2000); console.log(person.get('fullName')); ``` 运行结果: ``` fullName Observer fullName computed 西法 undefined fullName Observer ``` 明显可以看到区别: computed 根据被computed的属性变化,把函数的结果转成属性,当调用其get方法时,立即获取它的结果,如果这时被computed的属性的异步的,不会等待(可能是空或者被缓存起来的上一次的值),且不管被computed多少属性,只会调用一次。 observer 就持续监听属性,如果属性有变化后(就算是异步的)立即调用,可能会运行多次。 官网推荐使用computed,不要过度使用observer,同时这时强调,被computed的属性如果层级、数量较多(如fullName依赖firstName,lastName,而allName依赖fullName,而name依赖allName……),请梳理好这个关系,否则轻者占用资源,重则引起未知bug. ### ember-concurrency <a href="http://ember-concurrency.com/" target="_blank" rel="nofollow">ember-concurrency </a>是ember插件,主要解决异步回调问题。 例子: ```javascript getOrders: task(function*() { let orders = yield this.get('store').findAll(); this.set('orders', orders); }), _init: task(function*() { yield this.get('getOrders')(); //以下是需要orders异步取得之后才能运行的逻辑 }).on('init') ``` 在初始化时,先等待orders接口异步返回结果。目前只支持上述的generator 形式,不支持aysnc/await。如果不使用ember-concurrency,也可使用promise。 如需了解更多详情,推荐<a href="https://emberjs.com/" target="_blank" rel="nofollow">https://emberjs.com/</a>。
如果觉得有帮忙,您可以在本页底部留言。
相关推荐:
从youtube观看记录分析时长
Webpack深入浅出plugin
Webpack自动更新php静态资源文件名hash
Webpack构建流程之源码分析
Webpack基于scss生成css独立文件
Webpack深入浅出loader
移动端浏览器真机调试的几种方法
接入台湾超商门店地址选择
Ember之Handlebars模板引擎
Mac高频快捷键之前端篇
简述浏览器缓存之cookie
浏览器打开页面的过程中发生了什么
Git命令简化笔记
PHP实现微信JS-SDK权限验证
SQL快速运用指南
如何用正确的姿势写HTML
正则表达式实例解析
……
更多
<
《鼠疫》读后感,人人携带鼠疫
《呼啸山庄》读后感,偏激的爱情
>
全部留言
我要留言
内容:
网名:
邮箱:
个人网站:
发表
全部留言