运行时问题
空白应用
🌐 Blank App
我的 应用没有错误。为什么它显示空白屏幕?
这种情况发生有几个不同的原因。如果你无法在 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
对于 @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 补丁以支持 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
为什么我的自定义组件/指令不起作用?
有几件事你可以检查一下。请确保:
🌐 There are a few things you can check. Make sure:
- 你的选择器没有任何拼写错误。
- 你正确地将选择器用作属性、元素或类。
- 你的选择器具有正确的语法:
[attr]如果它是一个属性选择器element如果它是一个元素选择器.class如果它是一个类选择器
这是使用属性选择器的示例:
🌐 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
为什么我的点击事件有延迟?
一般来说,我们建议仅将 (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 变更检测运行得非常频繁?
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 的文件。将以下代码放入该文件中:
🌐 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 应用时,通过 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
某些组件,例如 ion-input 上的 counterFormatter 和 ion-range 上的 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.
请参阅其 MDN 页面 了解更多关于 this 在 JavaScript 中如何工作的 信息。
🌐 See its MDN page for more information on how this works in JavaScript.