关于app跳转vueh5页面时获取url附带的参数_tutorial第二部分-路由参数

紧接着Tutorial-第一部分回顾,继续往super-rental应用添加更有趣的功能。当用户点击列表时可以进入一个详情页面,详情页面可以展示一张更大的地图。

f2080926e78d4313c13f15f9a17bcc1c.png

本篇最后效果

效果图

本篇学习要点:

  • 在路由中使用动态参数
  • 组件的路由上使用动态参数
  • 可以访问路由器的组件测试
  • 通过动态参数段访问路由参数
  • 在不同的测试用例中共享公共代码

在路由中使用动态参数

目前Ember应用的首页列表还是无法点击的,我们可以想象一下,平常在网上冲浪的时候,如果从一个列表点击进入到一个详情页面通常的URL路径是这样的:/列表页面URL/某个数据的id。那么同理rental列表也可以做到,路径是这样的:/rentals/grand-old-mansion。grand-old-mansion就是数据的id。

之所以能接收参数需要修改的路由配置。

ember g route rental

修改路由的默认路径。

import EmberRouter from '@ember/routing/router';import config from './config/environment';export default class Router extends EmberRouter {  location = config.locationType;  rootURL = config.rootURL;}Router.map(function() {  this.route('about');  this.route('contact', { path: '/getting-in-touch' });  this.route('rental', { path: '/rentals/:rental_id' });});

注意路由设置路径里面。:rental_id 是一个动态参数,前面是有一个冒号的。这个就是一个动态参数,你可以理解为一个占位符,在访问请求的时候会自动替换成数据的id。

组件的路由上使用动态参数

修改rental.hbs,在中传递动态参数。

{{!-- app/components/rental.hbs --}}    {{!-- 调用Image组件,组件上有两个HTML属性,这两个HTML属性会传递到组件内部的...attributes上 --}}    <:image src="%7B%7B@rental.image%7D%7D">  

{{!-- 添加一个连接,跳转到路由rental上 --}} {{@rental.title}}

Owner: {{@rental.owner}}
Type: {{@rental.type}}
Location: {{@rental.city}}
Number of bedrooms: {{@rental.bedrooms}}

主要看这一行

在调用LinkTo跳转组件的时候传递了一个@model参数,页面刷新后,鼠标移动到首页图片上,可以看到浏览器底部的状态栏上显示的路径有一个undefine。这是怎么回事呢??

92c41dc17a0e7a888a2b19dc8538fe18.png

链接上是一个undefined

如果还有印象,前面文章中在路由index.js里面的传递过来的数据是没有包含id属性值的。由于没有id,整个模型就没有id,获取不到自然就是一个空。

修改index.js的取值,增加一个id属性。

// app/routes/index.jsimport Route from '@ember/routing/route';export default class IndexRoute extends Route {    // 使用异步方式返回,也就是说,路由一进来之后调用到model方法,    //  不会等到model方法执行完毕,它就会先转到模板上。    // 进入本路由的时候就会自动调用这个方法。    async model() {        // 通过fetch方法调用后端数据        // 更多有关fetch相关的信息请看:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API        let response = await fetch('/api/rentals.json');        // 解析数据        // let parsed = await response.json();        // return parsed;        // 解析JSON数据,获取attributes这个参数里面的数据        let { data } = await response.json();        // 通过map函数解析数据。        return data.map(model => {            // 拿到attributes参数            let { id, attributes } = model;            // 把数据做一个分类,'Condo','Townhouse','Apartment'归为一类,其他又做了微一类            let type;            let community = ['Condo','Townhouse','Apartment'];            if (community.includes(attributes.category)) {                type = 'Community';            } else {                type = 'Standalone';            }            return { id, type, ...attributes };        });    }}

注意这两行的改动。

let { id, attributes } = model;return { id, type, ...attributes };
9a9b055ee9a0c1efd190728a0a1e4bd4.png

鼠标移动到链接上查看链接地址

修改之后,再看地址状态栏,可以看到是这样的一个地址:http://localhost:4200/rentals/urban-living

点击之后跳转一个空白页面,因为我们还没对这个子路由做任何处理,所以还是一个空白页面。先不急着添加详情页面,先通过测试用例验证新增的链接是否成功了

import { module, test } from 'qunit';import { setupRenderingTest } from 'ember-qunit';import { render } from '@ember/test-helpers';import { hbs } from 'ember-cli-htmlbars';module('Integration | Component | rental', function(hooks) {  setupRenderingTest(hooks);  test('测试Rental组件,验证组件模板上的HTML属性或者标签是否达到预期', async function(assert) {    // Set any properties with this.set('myProperty', 'value');    // Handle any actions with this.set('myAction', function(val) { ... });    //  渲染组件,模拟组件的调用等同于在hbs模板中调用    // await render(hbs``);    // 使用动态数据之后,需要调整测试用例,此前的测试用例测试的是静态数据,    // 先构造一个JSON数据,然后再在调用组件的时候传递过去。    this.setProperties({        rental: {            // 添加一个id属性            id: "grand-old-mansion",            title: 'Grand Old Mansion',            owner: 'Veruca Salt',            city: 'San Francisco',                location: {                lat: 37.7749,                lng: -122.4194,            },            category: 'Estate',            type: 'Standalone',            bedrooms: 15,            image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg',            description: 'This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests.'        }    });    // 调用组件时把构造的数据传递过去。    await render(hbs``);    // 断言组件模板的HTML标签    assert.dom('article').hasClass('rental');    assert.dom('article h3').hasText('Grand Old Mansion');    // 断言在rental.hbs添加的详情页面跳转链接    assert.dom('article h3 a').hasAttribute('href', '/rental/grand-old-mansion');    // 断言这个标签下是否包含文字内容    assert.dom('article .detail.owner').includesText('Veruca Salt');    assert.dom('article .detail.type').includesText('Standalone');    assert.dom('article .detail.location').includesText('San Francisco');    assert.dom('article .detail.bedrooms').includesText('15');    assert.dom('article .image').exists();    // 验证组件调用成功    assert.dom("article .map").exists();  });});

注意21行和43行位置,添加了一个id属性,然后断言模板页面上的href属性值。

保存之后,看用例测试结果,but。。。。具体没测试通过。这又是怎么肥四!!!!

对于这种有跳转的路由需要通过代码先关联路由。

在setupRenderingTest(hooks);方法之后增加如下3行代码。

hooks.beforeEach(function () {    this.owner.setupRouter();});

如果其他测试也发现报错,也需要添加这段代码。

通过动态参数段访问路由参数

增加详情页面处理,现在点击图片上面的链接跳转到的是一个空白页面。首先在路由rental.js增加查询代码,根据动态参数查询某个数据。

// app/routes/rental.jsimport Route from '@ember/routing/route';export default class RentalRoute extends Route {    async model(params) {        // 获取上面传递参数,参数的名字就是在router.js里面的定义的动态参数rental_id        let response = await fetch(`/api/rentals/${params.rental_id}.json`);        let { data } = await response.json();        // 拿到attributes参数        let { id, attributes } = data;        // 把数据做一个分类,'Condo','Townhouse','Apartment'归为一类,其他又做了微一类        let type;        let community = ['Condo','Townhouse','Apartment'];        if (community.includes(attributes.category)) {            type = 'Community';        } else {            type = 'Standalone';        }        return { id, type, ...attributes };    }}

代码和index路由的很相似,不同的是index获取的是所有数据,rental路由只根据id获取指定的数据。返回的是一条数据。

params.rental_id 这个参数是非常关键的,params是model的入参,这个入参会自动把动态段参数rental_id封装进去。直接获取即可。

详细信息页面

为了展示点击之后的详情页面信息,新增一个子组件用于展示,这个页面会直接展示大图片,和标题。

ember g component rental/detailed
{{!-- app/components/rental/details.hbs 内容和rental模板的基本一致 --}}

{{@rental.title}}

Nice find! This looks like a nice place to stay near {{@rental.city}}.

Share on Twitter <:image src="%7B%7B@rental.image%7D%7D">

About {{@rental.title}}

Owner: {{@rental.owner}}
Type: {{@rental.type}} – {{@rental.category}}
Location: {{@rental.city}}
Number of bedrooms: {{@rental.bedrooms}}

{{@rental.description}}

修改app/templates/rental.hbs,在模板中调用新增的子组件detailed,页面刷新后,点击首页列表的标题。

9bf2960b59f021395c1126093ddfc92e.png

详情页面

效果完美,跳转到一个详情页面,页面上展示一张大图地图,再通过测试用例验证我们的代码。

// tests/acceptance/super-renlats.jsimport { module, test } from 'qunit';import { click, visit, currentURL } from '@ember/test-helpers';import { setupApplicationTest } from 'ember-qunit';module('Acceptance | super rentals', function(hooks) {  setupApplicationTest(hooks);  hooks.beforeEach(function() {      this.owner.setupRouter();  });  test('visiting /', async function(assert) {  // 模拟访问项目,等效于在浏览器输入http://localhost:4200/然后按enter。  await visit('/');  // 相当于进入首页之后,断言当前的URL是/  assert.equal(currentURL(), '/');  // 断言首页是否有h2标签,并且标签里面的内容是Welcome to Super Rentals!  assert.dom('h2').hasText('Welcome to Super Rentals!');  // 通过class属性层级找到按钮  断言按钮的内容是About Us  assert.dom('.jumbo a.button').hasText("About Us");      // 测试导航条      assert.dom('nav').exists();      assert.dom('h1').hasText('SuperRentals');      assert.dom('p').hasText("We hope you find exactly what you're looking for in a place to stay.");  // 触发事件,等同于你页面上点击了按钮,然后跳转到about路由下  await click('.jumbo a.button');  // 断言是否正确跳转到about路由      assert.equal(currentURL(), '/about');  });  //  test('测试首页列表的点击链接', async function(assert) {      await visit('/');      assert.dom('.rental').exists({ count: 3 });      await click('.rental :first-of-type a');      assert.equal(currentURL(), '/rentals/grand-old-mansion');  });  // 测试详情页,  test('测试<:detailed>页面,点击跳转到rentals/grand-old-mansion', async function(assert) {      await visit('/rentals/grand-old-mansion');      assert.equal(currentURL(), '/rentals/grand-old-mansion');      assert.dom('nav').exists();      assert.dom('h1').containsText('SuperRentals');      assert.dom('h2').containsText('Grand Old Mansion');      assert.dom('.rental.detailed').exists();  });  // 测试about页面,访问/about路由  test('visiting /about', async function(assert) {  // 测试进入路由about成功    await visit('/about');  // 断言当前的路由是/about  assert.equal(currentURL(), '/about');  // 断言h2标签的内容是About Super Rentals  assert.dom('h2').hasText('About Super Rentals');      // 测试导航条      assert.dom('nav').exists();      assert.dom('h1').hasText('SuperRentals');      assert.dom('p').hasText("The Super Rentals website is a delightful project created to explore Ember.      By building a property rental site, we can simultaneously imagine traveling      AND building Ember applications.");  // 断言有Contact Us按钮  assert.dom('.jumbo a.button').hasText('Contact Us');  // 触发点击事件,进入contact路由  await click('.jumbo a.button');  // 断言进入contact成功,因为自定义了路由URL,所以要判断当期路径和getting-in-touch是否一致  assert.equal(currentURL(), '/getting-in-touch');  });  //  测试contact页面,访问/getting-in-touch  test('visiting /getting-in-touch', async function(assert) {    await visit('/getting-in-touch');  assert.equal(currentURL(), '/getting-in-touch');  assert.dom('h2').hasText('Contact Us');  assert.dom('a.button').hasText('About');      // 测试导航条      assert.dom('nav').exists();      assert.dom('h1').hasText('SuperRentals');  await click('.jumbo a.button');  assert.equal(currentURL(), '/about');  });});
ea10906350723abaddb8c83a9be84027.png

所有测试通过

如果发现还有其他测试无法通过需要修改一些路由文件的的请求URL。

一个是app/routes/index.js,一个是app/routes/rental.js

把里面的URL地址前缀http://location:4200删除。

比如:

let response = await fetch(`http://location:4200/api/rentals/${params.rental_id}.json`);

改为

let response = await fetch(`/api/rentals/${params.rental_id}.json`);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值