运行时问题
空白应用
¥Blank App
我的应用中没有错误。为什么显示空白屏幕?
¥I have no errors in my app. Why does it show a blank screen?
发生这种情况的原因有多种。如果你无法在 Ionic 论坛 上找到解决方案,请确保:
¥There are several different reasons this can happen. If you are unable to find a solution on the Ionic forums, make sure:
-
较旧的浏览器/Android 版本不包含 Polyfills
¥Polyfills are not included for older browser/versions of android
对于 @angular/cli@7.3
或以上的项目,polyfills 将自动包含在内。对于之前创建的项目,需要手动启用 polyfills。
¥For projects with @angular/cli@7.3
or above, polyfills will automatically be included. For project created before that, polyfills need to be manually enabled.
在 src/polyfills.ts
中,你必须启用所有 ES6 polyfill 才能支持 Android 4.4。
¥In src/polyfills.ts
, you must enabled all ES6 polyfills for Android 4.4 support.
或者,可以更新项目以使用最新版本的 @angular/cli
包和 @angular-devkit
包,并在 angular.json
的构建选项对象中包含 es5BrowserSupport
选项:
¥Alternatively, a project could be updated to use the latest release of the @angular/cli
package & @angular-devkit
packages and include the es5BrowserSupport
option in the angular.json
's build options object:
"input": "src/global.scss"
}
],
- "scripts": []
+ "scripts": [],
+ "es5BrowserSupport": true
},
"configurations": {
"production": {
这将自动包含需要它们的旧浏览器的填充。
¥This will automatically include the polyfills for older browsers that need them.
指令不起作用
¥Directive Not Working
为什么我的自定义组件/指令不起作用?
¥Why is my custom component/directive not working?
你可以检查一些事项。确保:
¥There are a few things you can check. Make sure:
-
你的选择器没有任何拼写错误。
¥Your selector doesn't have any misspellings.
-
你正确地将选择器用作属性、元素或类。
¥You're using the selector correctly as an attribute, element or class.
-
你的选择器具有正确的语法:
¥Your selector has the proper syntax:
-
[attr]
(如果是属性选择器)¥
[attr]
if it's an attribute selector -
element
(如果是元素选择器)¥
element
if it's an element selector -
.class
(如果是类选择器)¥
.class
if it's a class selector
-
这是使用属性选择器的示例:
¥Here's an example using an attribute selector:
@Directive({
selector: '[my-dir]' // <-- [my-dir] because it is an attribute
}) // Could be my-dir, [my-dir], .my-dir
class MyDir {
constructor() {
console.log('I'm alive!');
}
}
@Component({
// We add my-dir as an attribute to match the directive's selector
template: `<div my-dir>Hello World</div>`,
// Alternatively, if you were attaching the directive to an element it would be:
// template: `<my-dir>Hello World</my-dir>`
// and if you were attaching by class the template would be:
// template: `<div class="my-dir">Hello World</div>`
directives: [MyDir] // <-- Don't forget me! (only if your ionic-angular version is below RC0)
})
class MyPage { }
点击延迟
¥Click Delays
为什么我的点击事件有延迟?
¥Why is there a delay on my click event?
一般来说,我们建议仅将 (click)
事件添加到通常可点击的元素中。这包括 <button>
和 <a>
元素。这提高了可访问性,因为屏幕阅读器将能够判断该元素是可点击的。
¥In general, we recommend only adding (click)
events to elements that are
normally clickable. This includes <button>
and <a>
elements. This improves
accessibility as a screen reader will be able to tell that the element is
clickable.
但是,你可能需要将 (click)
事件添加到通常不可单击的元素。当你执行此操作时,从单击元素到事件触发,你可能会遇到 300ms
延迟。要消除此延迟,你可以将 tappable
属性添加到元素中。
¥However, you may need to add a (click)
event to an element that is not
normally clickable. When you do this you may experience a 300ms
delay from the
time you click the element to the event firing. To remove this delay, you can
add the tappable
attribute to your element.
<div tappable (click)="doClick()">I am clickable!</div>
Angular 变化检测
¥Angular Change Detection
为什么当我的组件初始化时,Angular 变更检测运行得非常频繁?
¥Why does Angular change detection run very frequently when my components are initializing?
Angular 使用名为 zone.js 的库来帮助确定何时运行更改检测。
¥Angular uses a library called zone.js which helps it determine when to run change detection.
从 zone.js 0.8.27
开始,Web 组件的某些 API 也会导致更改检测运行。当大量组件初始化时,这可能会产生不良的副作用,即你的应用速度变慢。
¥As of zone.js 0.8.27
, certain APIs for Web Components also cause change
detection to run. This can have the undesirable side effect of your app
slowing down when a large number of components are initializing.
为了防止这种情况发生,可以禁用管理这部分更改检测的 zone.js 标志。在应用的 src
目录中,创建一个名为 zone-flags.ts
.txt 的文件。将以下代码放入文件中:
¥To prevent this from happening, the zone.js flag that manages this portion of
change detection can be disabled. In the src
directory of your application,
create a file called zone-flags.ts
. Place the following code into the file:
(window as any).__Zone_disable_customElements = true;
然后需要将 zone-flags.ts
文件导入到应用的 polyfills.ts
文件中。请务必在导入 zone.js
之前导入:
¥The zone-flags.ts
file then needs to be imported into your application's
polyfills.ts
file. Be sure to import it before zone.js
is imported:
...
import './zone-flags.ts';
import 'zone.js/dist/zone'; // Included with Angular CLI
...
此更改只会影响依赖 zone.js 0.8.27
或更高版本的应用。旧版本不会受到此更改的影响。
¥This change will only affect applications that depend on zone.js 0.8.27
or
newer. Older versions will not be affected by this change.
通过创建 Ionic 应用时会自动包含此标志
¥This flag is automatically included when creating an Ionic app via
Ionic CLI。
Cordova 插件无法在浏览器中运行
¥Cordova plugins not working in the browser
在开发过程中的某个时刻,你可能会尝试调用 Cordova 插件,但会收到警告:
¥At some point in your development you may, try to call Cordova plugin, but get a warning:
[Warning] Native: tried calling StatusBar.styleDefault, but Cordova is not
available. Make sure to include cordova.js or run in a device/simulator
(app.bundle.js, line 83388)
当你尝试调用原生插件但 Cordova 不可用时,会发生这种情况。值得庆幸的是,Ionic Native 会打印出一个很好的警告,而不是错误。
¥This happens when you try to call a native plugin, but Cordova isn't available. Thankfully, Ionic Native will print out a nice warning, instead of an error.
在其他情况下,如果插件未通过 Ionic Native 使用,插件可能会打印更加模糊的警告。
¥In other cases where the plugin is not being used through Ionic Native, plugins can print a much more obscure warning.
EXCEPTION: Error: Uncaught (in promise): TypeError: undefined is not an object
(evaluating 'navigator.camera.getPicture')
如果发生这种情况,请在真实设备或模拟器上测试插件。
¥If this happens, test the plugin on a real device or simulator.
提供者的多个实例
¥Multiple instances of a provider
如果你在每个组件中注入一个提供程序,因为你希望它可供所有组件使用,那么你最终会得到该提供程序的多个实例。如果你希望子组件可以使用该提供程序,则应该在父组件中注入该提供程序一次。
¥If you inject a provider in every component because you want it available to all of them you will end up with multiple instances of the provider. You should inject the provider once in the parent component if you want it to be available to the child components.
let id = 0;
export class MyService {
id: number;
constructor() {
this.id = id++;
}
}
@Component({
selector: 'my-component',
template: 'Hello World',
providers: [MyService], // <-- Creates a new instance of MyService :(
}) // Unnecessary because MyService is in App's providers
class MyComp {
// id is 1, s is a different MyService instance than MyApp
constructor(s: MyService) {
console.log('MyService id is: ' + s.id);
}
}
@Component({
template: '<my-component></my-component>',
providers: [MyService], // MyService only needs to be here
directives: [MyComp],
})
class MyApp {
// id is 0
constructor(s: MyService) {
console.log('MyService id is: ' + s.id);
}
}
在函数回调中访问 this
返回 undefined
¥Accessing this
in a function callback returns undefined
某些组件(例如 Ionic 输入上的 counterFormatter 和 Ionic 范围上的 pinFormatter)允许开发者传递回调。如果你计划从回调上下文中访问 this
,则绑定正确的 this
值非常重要。在使用 Angular 组件或在 React 中使用类组件时,你可能需要访问 this
。绑定 this
有两种方式:
¥Certain components, such as counterFormatter on ion-input and pinFormatter on ion-range, allow developers to pass callbacks. It's important that you bind the correct this
value if you plan to access this
from within the context of the callback. You may need to access this
when using Angular components or when using class components in React. There are two ways to bind this
:
绑定 this
的第一种方法是在函数实例上使用 bind()
方法。如果你想传递一个名为 counterFormatterFn
的回调,那么你可以写 counterFormatterFn.bind(this)
。
¥The first way to bind this
is to use the bind()
method on a function instance. If you want to pass a callback called counterFormatterFn
, then you would write counterFormatterFn.bind(this)
.
绑定 this
的第二种方法是在定义回调时使用 箭头函数。这是可行的,因为 JavaScript 不会为箭头函数创建新的 this
绑定。
¥The second way to bind this
is to use an arrow function when defining the callback. This works because JavaScript does not create a new this
binding for arrow functions.
有关 this
如何在 JavaScript 中工作的更多信息,请参阅其 MDN 页面。
¥See its MDN page for more information on how this
works in JavaScript.