亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

跨平臺應用開發入門教程

標簽:
移動開發
概述

跨平台应用开发是指使用一种编程语言或工具创建可以在多种操作系统和设备上运行的应用程序,这可以显著减少开发时间和成本。通过跨平台开发,开发者可以利用一套代码库来支持多个平台,从而提高开发效率并简化维护工作。本文详细介绍了React Native、Flutter和Xamarin等主流跨平台开发框架的优势和适用场景,并提供了详细的开发和配置指南。

跨平台应用开发简介
什么是跨平台应用开发

跨平台应用开发是指使用一种编程语言或工具创建可以在多种操作系统和设备上运行的应用程序。这包括但不限于iOS、Android、Windows和Web平台。通过跨平台开发,开发者可以利用一套代码库来支持多个平台,从而减少开发时间和成本。

跨平台应用开发的优势

跨平台应用开发的优势主要体现在以下几个方面:

  1. 节省开发时间:使用跨平台框架,开发者可以使用同一套代码库在多个平台上部署应用,减少了重复编码的工作量。
  2. 降低开发成本:由于代码重用性高,跨平台应用开发可以显著降低开发成本。开发者只需维护一个代码库。
  3. 提高开发效率:跨平台应用开发框架提供了丰富的API和工具,帮助开发者快速构建应用,提高开发效率。
  4. 简化维护:跨平台应用的维护相对简便,因为只需在一个地方进行修改,即可同步应用在多个平台上的更新。
跨平台应用开发的常见框架和工具

跨平台应用开发领域有许多框架和工具供开发者选择。以下是一些常用的跨平台应用开发框架:

  1. React Native:由Facebook开发的框架,使用JavaScript和React构建iOS和Android应用。React Native的组件库丰富,可以快速构建高质量的原生应用。
  2. Flutter:由Google开发的框架,使用Dart语言编写,支持iOS、Android、Web和桌面应用开发。Flutter以其高性能和丰富的UI库而著称。
  3. Xamarin:由微软开发的框架,使用C#语言编写,支持iOS、Android和Windows应用开发。Xamarin提供了丰富的API和工具来帮助开发者构建跨平台应用。

接下来我们详细介绍这些框架,并给出使用它们进行开发的基本代码示例。

React Native 示例代码

以下是一个简单的React Native应用代码示例,显示一个Hello World界面:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Hello, World!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  text: {
    fontSize: 24,
    color: '#3498db',
  },
});

Flutter 示例代码

以下是一个简单的Flutter应用代码示例,同样显示一个Hello World界面:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello World',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello World'),
        ),
        body: Center(
          child: Text(
            'Hello, World!',
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
    );
  }
}

Xamarin 示例代码

以下是一个简单的Xamarin应用代码示例,同样显示一个Hello World界面:

using System;
using Xamarin.Forms;

namespace HelloWorldApp
{
    public class App : Application
    {
        public App()
        {
            MainPage = new ContentPage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children = {
                        new Label {
                            HorizontalTextAlignment = TextAlignment.Center,
                            Text = "Hello, World!"
                        }
                    }
                }
            };
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}
选择合适的开发框架
常见的跨平台开发框架对比

跨平台开发框架各有特点,选择合适的框架对于项目的成功至关重要。以下是对React Native、Flutter和Xamarin的详细对比:

  1. React Native

    • 语言: JavaScript和React
    • 开发速度: 快速,因为React Native使用了现有的React组件库
    • 性能: 较好,但可能不如原生应用
    • 社区支持: 强大,有很多第三方库和组件可用
    • 适用场景: 适合快速原型开发和迭代,适用于大多数移动应用
  2. Flutter

    • 语言: Dart
    • 开发速度: 快速,Flutter内置了丰富的组件库
    • 性能: 高,Flutter使用自定义渲染引擎,性能接近原生应用
    • 社区支持: 逐渐增长,但相比React Native稍弱
      . 适用场景: 适合需要高质量UI和高性能的应用,适用于大多数移动和Web应用
  3. Xamarin
    • 语言: C#
    • 开发速度: 较慢,因为C#的学习曲线比JavaScript和Dart更陡峭
    • 性能: 高,与原生应用相当
    • 社区支持: 良好,尤其是对于企业级应用
    • 适用场景: 适合企业级应用,特别是需要与现有.NET生态系统集成的应用
如何根据项目需求选择合适的框架

选择合适的跨平台开发框架需要考虑以下几个因素:

  1. 开发速度和迭代周期

    • 如果项目需要快速原型开发和频繁迭代,React Native和Flutter是更好的选择。
    • 如果项目需要稳定的性能和长期维护,Xamarin可能更合适。
  2. 团队技术栈

    • 如果团队熟悉C#和.NET,Xamarin可能是更好的选择。
    • 如果团队熟悉JavaScript和React,React Native可能是更好的选择。
    • 如果团队熟悉Dart和Flutter,Flutter可能是更好的选择。
  3. 性能需求

    • 如果需要高性能和接近原生应用的性能,Flutter和Xamarin是更好的选择。
    • 如果性能要求不是特别高,React Native可能已经足够。
  4. UI复杂度
    • 如果项目需要复杂的自定义UI,Flutter可能更适合,因为它提供了丰富的组件库和自定义能力。
    • 如果UI相对简单,React Native和Xamarin都能满足需求。
Flutter vs React Native vs Xamarin

Flutter vs React Native

  1. 语言和生态系统

    • Flutter: 使用Dart语言,具有完整的开发环境和支持。
    • React Native: 使用JavaScript和React,拥有庞大的社区和丰富的第三方库。
  2. 性能

    • Flutter: 性能出色,自定义渲染引擎使其接近原生应用性能。
    • React Native: 性能较Flutter稍差,但仍能满足大多数应用需求。
  3. 开发速度
    • Flutter: 快速开发,内置丰富的组件库。
    • React Native: 快速开发,但由于JavaScript的动态性,可能需要更多调试。

Flutter vs Xamarin

  1. 语言和生态系统

    • Flutter: 使用Dart语言,社区支持逐渐增长。
    • Xamarin: 使用C#语言,与.NET生态系统高度集成。
  2. 性能

    • Flutter: 性能出色,接近原生应用。
    • Xamarin: 性能与原生应用相当,但可能稍逊于Flutter。
  3. 开发速度
    • Flutter: 快速开发,丰富的组件库。
    • Xamarin: 开发速度相对较慢,但适合长期维护。

React Native vs Xamarin

  1. 语言和生态系统

    • React Native: 使用JavaScript和React,社区支持强大。
    • Xamarin: 使用C#语言,与.NET生态系统高度集成。
  2. 性能

    • React Native: 性能较Flutter稍差,但能满足大多数应用需求。
    • Xamarin: 性能与原生应用相当,但可能稍逊于Flutter。
  3. 开发速度
    • React Native: 快速开发,丰富的第三方库。
    • Xamarin: 开发速度较慢,但适合企业级应用。
开发环境搭建
安装开发工具和IDE

安装开发工具和集成开发环境(IDE)是跨平台应用开发的第一步。不同的框架有不同的开发环境需求。以下是针对React Native、Flutter和Xamarin的安装指南。

React Native

  1. 安装Node.js和npm

    • 下载并安装Node.js,安装时会自动安装npm。
    • 验证安装是否成功:
      node -v
      npm -v
  2. 安装React Native CLI

    • 使用npm全局安装React Native CLI:
      npm install -g react-native-cli
  3. 安装Android Studio和Xcode

Flutter

  1. 安装Flutter SDK

    • 下载并安装Flutter SDK,参考官方文档
    • 设置环境变量:
      export PATH="$PATH:`pwd`/flutter/bin"
  2. 安装Android Studio和Xcode

  3. 配置Flutter环境
    • 安装Flutter插件:
      flutter doctor

Xamarin

  1. 安装Visual Studio

    • 下载并安装Visual Studio,确保选择包含Xamarin的开发工作负载。
    • 安装完成后,运行Visual Studio并根据提示安装必要的组件。
  2. 安装Xcode

    • 安装Xcode用于iOS开发。
  3. 配置Xamarin环境
    • 安装Xamarin插件,确保Visual Studio和Xcode之间的集成。
配置开发环境

配置开发环境是确保应用可以顺利构建和测试的重要步骤。

React Native

  1. 配置Android环境

    • 在Android Studio中配置Android虚拟设备或连接真实设备。
    • 配置环境变量:
      export ANDROID_HOME=/path/to/sdk
      export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
  2. 配置iOS环境
    • 在Xcode中配置iOS模拟器或连接真实设备。
    • 确保安装了Xcode命令行工具:
      xcode-select --install

Flutter

  1. 配置Android环境

    • 在Android Studio中配置Android虚拟设备或连接真实设备。
    • 配置环境变量:
      export ANDROID_HOME=/path/to/sdk
      export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
  2. 配置iOS环境
    • 在Xcode中配置iOS模拟器或连接真实设备。
    • 确保安装了Xcode命令行工具:
      xcode-select --install

Xamarin

  1. 配置Android环境

    • 在Visual Studio中配置Android虚拟设备或连接真实设备。
    • 配置环境变量:
      export ANDROID_HOME=/path/to/sdk
      export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
  2. 配置iOS环境
    • 在Xcode中配置iOS模拟器或连接真实设备。
    • 确保安装了Xcode命令行工具:
      xcode-select --install
连接模拟器或真实设备

连接模拟器或真实设备是测试应用的重要步骤。

React Native

  1. 启动模拟器

    • 对于Android:
      react-native run-android
    • 对于iOS:
      react-native run-ios
  2. 连接真实设备
    • 对于Android,确保设备已启用开发者模式并安装了USB调试驱动。
    • 对于iOS,确保已安装Xcode并配置了iOS设备。

Flutter

  1. 启动模拟器

    • 对于Android:
      flutter run -d android
    • 对于iOS:
      flutter run -d ios
  2. 连接真实设备
    • 对于Android,确保设备已启用开发者模式并安装了USB调试驱动。
    • 对于iOS,确保已安装Xcode并配置了iOS设备。

Xamarin

  1. 启动模拟器

    • 在Visual Studio中选择模拟器并运行项目。
    • 对于Android:
      dotnet build -t:Run -p:Configuration=Debug -p:Platform=Android
    • 对于iOS:
      dotnet build -t:Run -p:Configuration=Debug -p:Platform=iOS
  2. 连接真实设备
    • 对于Android,确保设备已启用开发者模式并安装了USB调试驱动。
    • 对于iOS,确保已安装Xcode并配置了iOS设备。
创建第一个跨平台应用
设计应用的基本结构

创建应用的基本结构是开发的第一步。应用的基本结构包括项目目录、主要文件和组件。

React Native

  1. 项目目录结构

    • 根目录:包含所有项目文件。
      ├── android
      ├── ios
      ├── assets
      ├── app.json
      ├── App.js
      ├── index.js
      └── package.json
  2. 主要文件
    • App.js: 应用的主入口文件。
    • package.json: 包含应用的依赖关系和配置信息。
    • index.js: 入口文件,启动应用。

Flutter

  1. 项目目录结构

    • 根目录:包含所有项目文件。
      ├── android
      ├── ios
      ├── lib
      ├── test
      ├── pubspec.yaml
      └── main.dart
  2. 主要文件
    • main.dart: 应用的主入口文件。
    • pubspec.yaml: 包含应用的依赖关系和配置信息。

Xamarin

  1. 项目目录结构

    • 根目录:包含所有项目文件。
      ├── HelloWorldApp
      ├── HelloWorldApp.Android
      ├── HelloWorldApp.iOS
      └── HelloWorldApp.Shared
  2. 主要文件
    • App.xaml.cs: 应用的主入口文件。
    • App.xaml: 应用的配置文件。
    • MainActivity.cs: Android主活动文件。
    • AppDelegate.cs: iOS主活动文件。
编写基础代码

编写基础代码是构建应用的关键步骤。以下是一个简单的应用示例,显示一个Hello World界面。

React Native

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Hello, World!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  text: {
    fontSize: 24,
    color: '#3498db',
  },
});

Flutter

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hello World',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Hello World'),
        ),
        body: Center(
          child: Text(
            'Hello, World!',
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
    );
  }
}

Xamarin

using System;
using Xamarin.Forms;

namespace HelloWorldApp
{
    public class App : Application
    {
        public App()
        {
            MainPage = new ContentPage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children = {
                        new Label {
                            HorizontalTextAlignment = TextAlignment.Center,
                            Text = "Hello, World!"
                        }
                    }
                }
            };
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}
运行和调试应用

运行和调试应用是确保应用正常工作的关键步骤。

React Native

  1. 运行应用

    • 对于Android:
      react-native run-android
    • 对于iOS:
      react-native run-ios
  2. 调试应用
    • 使用Chrome DevTools进行调试。

Flutter

  1. 运行应用

    • 对于Android:
      flutter run -d android
    • 对于iOS:
      flutter run -d ios
  2. 调试应用
    • 使用Dart DevTools进行调试。

Xamarin

  1. 运行应用

    • 在Visual Studio中选择模拟器或连接设备并运行项目。
    • 对于Android:
      dotnet build -t:Run -p:Configuration=Debug -p:Platform=Android
    • 对于iOS:
      dotnet build -t:Run -p:Configuration=Debug -p:Platform=iOS
  2. 调试应用
    • 使用Visual Studio内置的调试工具进行调试。
实战案例解析
分析一个简单的跨平台应用

以一个简单的待办事项应用为例,分析其开发过程和技术选型。

应用需求

假设我们需要开发一个简单的待办事项应用,用户可以添加、编辑和删除待办事项。

技术选型

选择React Native进行开发,因为它具有快速开发和良好的社区支持。

项目结构

项目结构如下:

├── android
├── ios
├── App.js
├── index.js
├── package.json
└── src
    ├── components
    │   ├── AddTodo.js
    │   ├── TodoItem.js
    │   └── TodosList.js
    └── App.js

代码示例

AddTodo.js (React Native)

import React from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';

const AddTodo = ({ addTodo }) => {
  const [newTodo, setNewTodo] = React.useState('');

  const handleAddTodo = () => {
    if (newTodo.trim()) {
      addTodo(newTodo);
      setNewTodo('');
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Add a new todo"
        value={newTodo}
        onChangeText={setNewTodo}
      />
      <Button title="Add" onPress={handleAddTodo} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 10,
  },
  input: {
    flex: 1,
    marginRight: 10,
    borderWidth: 1,
    padding: 5,
  },
});

export default AddTodo;

TodoItem.js (React Native)

import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

const TodoItem = ({ todo, onRemove }) => {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>{todo.text}</Text>
      <TouchableOpacity style={styles.removeButton} onPress={onRemove}>
        <Text style={styles.removeButtonText}>Remove</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 10,
    borderBottomWidth: 1,
    borderBottomColor: '#ddd',
  },
  text: {
    flex: 1,
  },
  removeButton: {
    backgroundColor: 'red',
    padding: 5,
    borderRadius: 5,
  },
  removeButtonText: {
    color: 'white',
  },
});

export default TodoItem;

TodosList.js (React Native)

import React from 'react';
import { View, FlatList } from 'react-native';
import TodoItem from './TodoItem';

const TodosList = ({ todos, onRemove }) => {
  return (
    <FlatList
      data={todos}
      renderItem={({ item }) => <TodoItem todo={item} onRemove={() => onRemove(item.id)} />}
      keyExtractor={(item) => item.id.toString()}
    />
  );
};

export default TodosList;

App.js (React Native)

import React from 'react';
import { View, StyleSheet } from 'react-native';
import AddTodo from './components/AddTodo';
import TodosList from './components/TodosList';

const App = () => {
  const [todos, setTodos] = React.useState([]);

  const addTodo = (text) => {
    const newTodo = { id: Math.random().toString(), text };
    setTodos([...todos, newTodo]);
  };

  const removeTodo = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

  return (
    <View style={styles.container}>
      <AddTodo addTodo={addTodo} />
      <TodosList todos={todos} onRemove={removeTodo} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 10,
  },
});

export default App;

项目结构 (Flutter)

├── android
├── ios
├── lib
│   ├── components
│   │   ├── add_todo.dart
│   │   ├── todo_item.dart
│   │   └── todos_list.dart
│   └── main.dart
├── pubspec.yaml
└── main.dart

代码示例 (Flutter)

add_todo.dart

import 'package:flutter/material.dart';

class AddTodo {
  final TextEditingController controller = TextEditingController();

  void addTodo(Function(String) addTodo) {
    if (controller.text.trim() != '') {
      addTodo(controller.text);
      controller.clear();
    }
  }

  Widget build(BuildContext context, Function(String) addTodo) {
    return Container(
      padding: EdgeInsets.all(10),
      child: Row(
        children: [
          Expanded(
            child: TextField(
              controller: controller,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Add a new todo',
              ),
            ),
          ),
          IconButton(
            icon: Icon(Icons.add),
            onPressed: () => addTodo(controller.text),
          ),
        ],
      ),
    );
  }
}

todo_item.dart

import 'package:flutter/material.dart';

class TodoItem extends StatelessWidget {
  final String text;
  final Function() onRemove;

  TodoItem({required this.text, required this.onRemove});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      child: Row(
        children: [
          Expanded(
            child: Text(
              text,
              style: TextStyle(fontSize: 18),
            ),
          ),
          IconButton(
            icon: Icon(Icons.remove_circle),
            onPressed: onRemove,
          ),
        ],
      ),
    );
  }
}

todos_list.dart

import 'package:flutter/material.dart';
import 'todo_item.dart';

class TodosList extends StatelessWidget {
  final List<String> todos;
  final Function(String) onRemove;

  TodosList({required this.todos, required this.onRemove});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: todos.length,
      itemBuilder: (context, index) {
        return TodoItem(
          text: todos[index],
          onRemove: () => onRemove(todos[index]),
        );
      },
    );
  }
}

main.dart

import 'package:flutter/material.dart';
import 'components/add_todo.dart';
import 'components/todos_list.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Todo App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: TodoApp(),
    );
  }
}

class TodoApp extends StatefulWidget {
  @override
  _TodoAppState createState() => _TodoAppState();
}

class _TodoAppState extends State<TodoApp> {
  List<String> todos = [];

  void addTodo(String todo) {
    setState(() {
      todos.add(todo);
    });
  }

  void removeTodo(String todo) {
    setState(() {
      todos.remove(todo);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Todo App'),
      ),
      body: Column(
        children: [
          AddTodo(addTodo: addTodo),
          TodosList(todos: todos, onRemove: removeTodo),
        ],
      ),
    );
  }
}

项目结构 (Xamarin)

├── HelloWorldApp
├── HelloWorldApp.Android
├── HelloWorldApp.iOS
└── HelloWorldApp.Shared

代码示例 (Xamarin)

MainPage.xaml.cs (Xamarin)

using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace HelloWorldApp
{
    public partial class MainPage : ContentPage
    {
        private List<string> todos = new List<string>();

        public MainPage()
        {
            InitializeComponent();
            BindingContext = this;
        }

        private void AddTodo(string text)
        {
            if (!string.IsNullOrEmpty(text))
            {
                todos.Add(text);
                todoList.ItemsSource = todos;
            }
        }

        private void RemoveTodo(string text)
        {
            todos.Remove(text);
            todoList.ItemsSource = todos;
        }
    }
}

MainPage.xaml (Xamarin)

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HelloWorldApp.MainPage">
    <StackLayout>
        <Entry x:Name="todoEntry" Placeholder="Add a new todo" />
        <Button Text="Add" Clicked="OnAddButtonClicked" />
        <ListView x:Name="todoList" ItemsSource="{Binding todos}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding .}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>
分享开发过程中的经验和教训

开发过程中会遇到各种挑战,以下是一些经验和教训:

  1. 选择合适的框架
    • 根据项目需求选择合适的框架,不要盲目追求最新技术。
  2. 社区支持
    • 利用社区资源,遇到问题时及时寻求帮助。
  3. 代码维护
    • 保持代码的整洁和可维护性,避免后期难以维护的问题。
  4. 性能优化
    • 关注应用性能,及时进行优化。
推荐学习资源和社区

以下是一些推荐的学习资源和社区:

  1. 慕课网
    • 提供丰富的跨平台开发课程。
    • 慕课网
  2. 官方文档
  3. Stack Overflow
  4. GitHub
    • 提供丰富的开源项目和代码示例。
    • GitHub
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消