mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-21 04:53:58 +08:00
feat(route): adds route-link
This commit is contained in:
21
packages/core/src/components.d.ts
vendored
21
packages/core/src/components.d.ts
vendored
@ -2546,31 +2546,30 @@ declare global {
|
|||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RouteLink as IonRouteLink
|
RouteLink as IonAnchor
|
||||||
} from './components/route-link/route-link';
|
} from './components/route-link/route-link';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLIonRouteLinkElement extends IonRouteLink, HTMLStencilElement {
|
interface HTMLIonAnchorElement extends IonAnchor, HTMLStencilElement {
|
||||||
}
|
}
|
||||||
var HTMLIonRouteLinkElement: {
|
var HTMLIonAnchorElement: {
|
||||||
prototype: HTMLIonRouteLinkElement;
|
prototype: HTMLIonAnchorElement;
|
||||||
new (): HTMLIonRouteLinkElement;
|
new (): HTMLIonAnchorElement;
|
||||||
};
|
};
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ion-route-link": HTMLIonRouteLinkElement;
|
"ion-anchor": HTMLIonAnchorElement;
|
||||||
}
|
}
|
||||||
interface ElementTagNameMap {
|
interface ElementTagNameMap {
|
||||||
"ion-route-link": HTMLIonRouteLinkElement;
|
"ion-anchor": HTMLIonAnchorElement;
|
||||||
}
|
}
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
"ion-route-link": JSXElements.IonRouteLinkAttributes;
|
"ion-anchor": JSXElements.IonAnchorAttributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace JSXElements {
|
namespace JSXElements {
|
||||||
export interface IonRouteLinkAttributes extends HTMLAttributes {
|
export interface IonAnchorAttributes extends HTMLAttributes {
|
||||||
router?: any;
|
href?: string;
|
||||||
url?: string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core';
|
||||||
import { CssClassMap } from '../../index';
|
import { CssClassMap } from '../../index';
|
||||||
import { BlurEvent, FocusEvent } from '../../utils/input-interfaces';
|
import { BlurEvent, FocusEvent } from '../../utils/input-interfaces';
|
||||||
import { getButtonClassMap, getElementClassMap } from '../../utils/theme';
|
import { getButtonClassMap, getElementClassMap, openURL } from '../../utils/theme';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -133,16 +133,16 @@ export class Button {
|
|||||||
|
|
||||||
const attrs = (TagType === 'button')
|
const attrs = (TagType === 'button')
|
||||||
? { type: this.type }
|
? { type: this.type }
|
||||||
: {};
|
: { href: this.href };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TagType
|
<TagType
|
||||||
{...attrs}
|
{...attrs}
|
||||||
class={buttonClasses}
|
class={buttonClasses}
|
||||||
disabled={this.disabled}
|
disabled={this.disabled}
|
||||||
href={this.href}
|
|
||||||
onFocus={this.onFocus.bind(this)}
|
onFocus={this.onFocus.bind(this)}
|
||||||
onKeyUp={this.onKeyUp.bind(this)}
|
onKeyUp={this.onKeyUp.bind(this)}
|
||||||
|
onClick={(ev) => openURL(this.href, ev)}
|
||||||
onBlur={this.onBlur.bind(this)}>
|
onBlur={this.onBlur.bind(this)}>
|
||||||
<span class='button-inner'>
|
<span class='button-inner'>
|
||||||
<slot name='icon-only'></slot>
|
<slot name='icon-only'></slot>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Listen, Prop, State } from '@stencil/core';
|
import { Component, Element, Listen, Prop, State } from '@stencil/core';
|
||||||
import { createThemedClasses, getElementClassMap } from '../../utils/theme';
|
import { createThemedClasses, getElementClassMap, openURL } from '../../utils/theme';
|
||||||
import { CssClassMap } from '../../index';
|
import { CssClassMap } from '../../index';
|
||||||
|
|
||||||
|
|
||||||
@ -104,10 +104,10 @@ export class Item {
|
|||||||
|
|
||||||
const clickable = !!(this.href || this.onclick || this.tappable);
|
const clickable = !!(this.href || this.onclick || this.tappable);
|
||||||
|
|
||||||
let TagType = 'div';
|
const TagType = clickable
|
||||||
if (clickable) {
|
? this.href ? 'a' : 'button'
|
||||||
TagType = this.href ? 'a' : 'button';
|
: 'div';
|
||||||
}
|
|
||||||
const attrs = (TagType === 'button')
|
const attrs = (TagType === 'button')
|
||||||
? {type: 'button'}
|
? {type: 'button'}
|
||||||
: {href: this.href};
|
: {href: this.href};
|
||||||
@ -125,7 +125,10 @@ export class Item {
|
|||||||
this.hasStyleChange = false;
|
this.hasStyleChange = false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TagType class={themedClasses} {...attrs}>
|
<TagType
|
||||||
|
{...attrs}
|
||||||
|
class={themedClasses}
|
||||||
|
onClick={(ev) => openURL(this.href, ev)}>
|
||||||
<slot name='start'></slot>
|
<slot name='start'></slot>
|
||||||
<div class='item-inner'>
|
<div class='item-inner'>
|
||||||
<div class='input-wrapper'>
|
<div class='input-wrapper'>
|
||||||
|
@ -7,24 +7,14 @@
|
|||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
#### router
|
#### href
|
||||||
|
|
||||||
any
|
|
||||||
|
|
||||||
|
|
||||||
#### url
|
|
||||||
|
|
||||||
string
|
string
|
||||||
|
|
||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
#### router
|
#### href
|
||||||
|
|
||||||
any
|
|
||||||
|
|
||||||
|
|
||||||
#### url
|
|
||||||
|
|
||||||
string
|
string
|
||||||
|
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import { Component, Prop } from '@stencil/core';
|
import { Component, Prop } from '@stencil/core';
|
||||||
|
import { openURL } from '../../utils/theme';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-route-link'
|
tag: 'ion-anchor'
|
||||||
})
|
})
|
||||||
export class RouteLink {
|
export class RouteLink {
|
||||||
@Prop() url: string;
|
|
||||||
|
|
||||||
// The instance of the router
|
@Prop() href: string;
|
||||||
@Prop() router: any;
|
|
||||||
|
render() {
|
||||||
|
return <a
|
||||||
|
href={this.href}
|
||||||
|
onClick={(ev) => openURL(this.href, ev)}><slot/></a>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ string
|
|||||||
boolean
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
#### pushURL()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Component, Element, Listen, Prop } from '@stencil/core';
|
import { Component, Element, Listen, Method, Prop } from '@stencil/core';
|
||||||
import { Config, DomController } from '../../index';
|
import { Config, DomController } from '../../index';
|
||||||
import { flattenRouterTree, readRoutes } from './utils/parser';
|
import { flattenRouterTree, readRoutes } from './utils/parser';
|
||||||
import { readNavState, writeNavState } from './utils/dom';
|
import { readNavState, writeNavState } from './utils/dom';
|
||||||
import { chainToPath, readPath, writePath } from './utils/path';
|
import { chainToPath, parsePath, readPath, writePath } from './utils/path';
|
||||||
import { RouteChain } from './utils/interfaces';
|
import { RouteChain } from './utils/interfaces';
|
||||||
import { routerIDsToChain, routerPathToChain } from './utils/matching';
|
import { routerIDsToChain, routerPathToChain } from './utils/matching';
|
||||||
|
|
||||||
@ -42,11 +42,8 @@ export class Router {
|
|||||||
this.state++;
|
this.state++;
|
||||||
window.history.replaceState(this.state, document.title, document.location.href);
|
window.history.replaceState(this.state, document.title, document.location.href);
|
||||||
}
|
}
|
||||||
if (!this.busy) {
|
|
||||||
console.debug('[OUT] hash changed -> write nav state');
|
|
||||||
this.writeNavStateRoot();
|
this.writeNavStateRoot();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Listen('body:ionNavChanged')
|
@Listen('body:ionNavChanged')
|
||||||
protected onNavChanged(ev: CustomEvent) {
|
protected onNavChanged(ev: CustomEvent) {
|
||||||
@ -63,21 +60,34 @@ export class Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isPop = ev.detail.isPop === true;
|
const isPop = ev.detail.isPop === true;
|
||||||
this.writePath(chain, isPop);
|
const path = chainToPath(chain);
|
||||||
|
this.writePath(path, isPop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Method()
|
||||||
|
pushURL(url: string) {
|
||||||
|
this.writePath(parsePath(url), false);
|
||||||
|
return this.writeNavStateRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private writeNavStateRoot(): Promise<any> {
|
private writeNavStateRoot(): Promise<any> {
|
||||||
const node = document.querySelector('ion-app');
|
if (this.busy) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
const currentPath = this.readPath();
|
const currentPath = this.readPath();
|
||||||
|
if (!currentPath) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
const direction = window.history.state >= this.state ? 1 : -1;
|
const direction = window.history.state >= this.state ? 1 : -1;
|
||||||
if (currentPath) {
|
const node = document.querySelector('ion-app');
|
||||||
const {chain} = routerPathToChain(currentPath, this.routes);
|
const {chain} = routerPathToChain(currentPath, this.routes);
|
||||||
return this.writeNavState(node, chain, direction);
|
return this.writeNavState(node, chain, direction);
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
private writeNavState(node: any, chain: RouteChain, direction: number): Promise<any> {
|
private writeNavState(node: any, chain: RouteChain, direction: number): Promise<any> {
|
||||||
|
if (this.busy) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
this.busy = true;
|
this.busy = true;
|
||||||
return writeNavState(node, chain, 0, direction)
|
return writeNavState(node, chain, 0, direction)
|
||||||
.catch(err => console.error(err))
|
.catch(err => console.error(err))
|
||||||
@ -89,8 +99,7 @@ export class Router {
|
|||||||
return readNavState(root);
|
return readNavState(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
private writePath(chain: RouteChain, isPop: boolean) {
|
private writePath(path: string[], isPop: boolean) {
|
||||||
const path = chainToPath(chain);
|
|
||||||
this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state);
|
this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,3 +62,14 @@ export function getClassMap(classes: string | undefined): CssClassMap {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function openURL(url: string, ev: Event) {
|
||||||
|
if (url && url.indexOf('://') === -1) {
|
||||||
|
const router = document.querySelector('ion-router');
|
||||||
|
if (router) {
|
||||||
|
ev && ev.preventDefault();
|
||||||
|
return router.componentOnReady().then(() => router.pushURL(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user