热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter入门——Flutter功能概览

IT之家12月5日消息:今天谷歌官方宣布Flutter的1.0版本正式发布!Flutter是Google打造的UI工具包,帮助你通过一套代码同时在iOS和Android上构建媲美原

IT之家12月5日消息: 今天谷歌官方宣布Flutter 的 1.0 版本正式发布!Flutter是Google打造的UI工具包,帮助你通过一套代码同时在iOS 和Android上构建媲美原生体验的精美应用 —— 2018”

Google 刚公布Kotlin 成为 Android 官方开发语言没多久,Flutter就发布了 1.0 版本。虽然说搞不明白 google 的战略意图,但作为一个IT人员,既然有了新东西,尤其跟自己的工作息息相关,就得去了解一下了。

kotlin 自不必说,其大概功能以及优缺点已经在之前博客中进行了简单的说明:
从Java的角度看kotlin特性(一)
从Java的角度看kotlin特性(二)
其中已经对比了javakotlin部分差异以及功能。

那么Flutter到底是什么?能做些什么?要想弄明白这个,我们可以看一下官方说明:

Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.

ok,一个跨平台的移动端框架,适用于Android 和 IOS 平台,开源,不同平台使用相同代码。

其实这种框架或者说想法从来不曾缺少,事实上,在很久之前就开始了跨平台的研究,各种跨平台理念层出不穷:

  • H5+原生
  • Javascript开发+原生渲染 (React Native、Weex等)

像上面两种方式是使用最多也是最通用的,那么Flutter 一个“初来乍到”的概念,对比之前的方式又有什么新颖之处?

从各种资料来看Flutter 宣扬的 “高明” 之处主要在于:

  1. 热重载
  2. 60FPS

热重载得益于Dart 语言的 AOT 和 JIT 两种运行模式。
60FPS则是由于自身实现了完整的2D图形引擎。

既然说优点这么多,那总得试一下效果才好;
首先我们尝试一下在Android(IOS)端开发过程。

一、 准备工作

按照官方文档,我们将 Flutter 环境安装完成。由于国外网站都被墙了,因此我们可以查看 Flutter 中文网 来完成预备步骤。

如果是Android 开发人员,这里我们直接 查看这里 入门: 在Windows上搭建Flutter开发环境

需要注意的是,Flutter SDK 是存放于 GITHUB 的一个开源项目,因此我们可以直接从GITHUB 上克隆下来。

然后中间教程会有说到需要执行:

flutter doctor

这相当于一个Flutter 的全局检查功能,所有错误或者缺少的东西,都会被检查到。

还有,Flutter 是依赖Dart SDK 的,所幸Flutter 会自动安装 Dart 到自身目录下,一般而言是这样的:

《Flutter入门——Flutter功能概览》

因此我们不需要单独再去下载其他功能包。

目前开发Android 使用的应该都是 AndroidStudio ,我们打开 AS 软件,然后搜索两个 plugin :

  1. flutter
  2. dart

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

安装后重启AS,就会在启动后看到这样的功能按钮:

《Flutter入门——Flutter功能概览》

当然,如果AS提示有错误,则可能是Flutter SDK路径未自动配置,想这样配置一下 Flutter 和 Dart

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

如果AS启动后,首页界面没有 Start a new Flutter project这个选项,则可能是有个 plugin 没打开,这是只要把这个插件置于打开状态就好:

《Flutter入门——Flutter功能概览》

二、 创建 Flutter Project

然后我们就可以创建一个flutter 项目了:

点击Start a new Flutter project,可能会有些慢,稍等几十秒,然后系统会弹出需要创建的 flutter 项目类型类型。

《Flutter入门——Flutter功能概览》

1、 创建 flutter application

flutter application 是指创建一个正常的Flutter ,即创建一个适用于Android 及 IOS移动设备的项目,创建过程由 idea 一键完成,并不需要有多复杂的步骤。

《Flutter入门——Flutter功能概览》

上面一次含义为:

  1. Project 项目名称,和一般项目相同
  2. Flutter SDK 目录,这个一般会自动配置
  3. 项目所在目录
  4. 项目介绍

这些和普通创建一个项目是没有区别的,点击 next ,配置项目其他信息:

《Flutter入门——Flutter功能概览》

先需要配置一下包名,包名对于android 和ios 来说,不同应用应该不同。

然后需要根据需求,配置 ios 是否需要加入swift支持,android 是否需要加入 kotlin支持。

然后点击 finish,项目创建成功:

《Flutter入门——Flutter功能概览》

  • androidios 目录下分别对应两个平台各自的代码。
  • lib 目录包含了我们将要编写的业务逻辑代码,这里会自动生成一个入口界面:main.dart
  • test 目录用于单元测试或者组件测试
  • pubspec.yaml 是所有配置所在的地方,其中指明了:项目名,项目描述,项目当前版本号,sdk版本,运行或开发时依赖等内容。

观察AS界面,可以看到如下部分:

《Flutter入门——Flutter功能概览》

在真机已连接,入口类已设定情况下,点击三角箭头,应用就会安装到真机上。然后就可以使用热更新进行快速高效的开发了。

《Flutter入门——Flutter功能概览》

这里我们不仔细讨论Flutter 如何编码,只用一个现有的例子来查看显示效果,主要模仿华容道进行一个关卡设置,可以针对卡片进行上下左右滑动:

代码可以在 github 上下载查看:checkpoint_one.dart

PlusPlugins.dart 代码在另一个类中,这里直接写出来:

///
/// 额外添加的class系列
///
///定义系列的返回特定类型的函数,只有一个参数
typedef RBoolOneP = bool Function(T obj);
typedef RVoidOneP = void Function(T obj);
typedef RIntOneP = int Function(T obj);
typedef BBB = int Function(List obj);
///定义系列的返回特定类型的函数,无参数
typedef RBoolZeroP = bool Function();
typedef RVoidZeroP = void Function();
typedef RIntZeroP = int Function();

这里只用 debug 包进行演示,只要知道 release 比 debug 模式要顺畅就可以了:

《Flutter入门——Flutter功能概览》

可以看到,流畅效果不比 原生的差了。

2 、创建 Flutter Plugin

Flutter Plugin 从名字就可以看出,主要是一个插件,主要作为一个中间件,来连接原生 与 flutter 。

flutter 如果需要调用原生功能,比如照相机等硬件设备时,自身肯定无法完成这种功能,这时就需要使用 plugin 插件,通过相互通信,让原生来调用设备能力。

Flutter Plugin 创建流程和 Application 差不多,创建完成后,代码结构如下所示:

《Flutter入门——Flutter功能概览》

lib下 的文件成为了 插件类,我们可以在其中约定原生与flutter 相互调用的方法,如,我们在 flutter_plugin.dart中添加如下代码:

import 'dart:async';
import 'package:flutter/services.dart';
///编写插件的部分
class FlutterPlugin {
///方法通道标识,用于在 平台间 调用接口,该字符串为多平台统一的
static const MethodChannel _channel = const MethodChannel('flutter_plugin');
///通道可调用的方法/参数: 需要设置为异步(确定不会阻塞主线程)
static Future get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
///获取随机的double值
static Future get randomCode async {
return await _channel.invokeMethod('getRandomCode');
}
}

然后在项目的 android 目录下,编写插件对应的android 实现(kotlin 语言)

《Flutter入门——Flutter功能概览》

然后在 example/lib/main.dart 中,可以测试插件是否编写的正确:

《Flutter入门——Flutter功能概览》

注意,example 是idea 自动帮我们生成的一个内置 project,我们可以看一下example/pubspec.yaml 文件:

《Flutter入门——Flutter功能概览》

即,example 项目引用了我们创建的 plugin ,所以,才可以使用该 project 测试插件的功能。

这里还有一个问题,flutter_plugin 插件如何知道 flutter 与 原生哪个类进行对应的?事实上,在 flutter_plugin/pubspec.yaml中也进行了指定:

《Flutter入门——Flutter功能概览》

红线标识部分说明了该插件对应了 com.knowledge.mnlin.flutter_plugin包下的 FlutterPlugin类,于是项目编译时,在 flutter_plugin/example/android/项目里,GeneratedPluginRegistrant会对指定的插件进行 注册。

《Flutter入门——Flutter功能概览》

说了那么多,来看一下,插件是否可以正常运行;我们指定这个类为入口,然后真机测试:

《Flutter入门——Flutter功能概览》

在这个类中,进行原生调用,然后查看效果(注意,这里放了一个三秒间隔的循环定时获取随机数):

class _MyAppState extends State {
String _platformVersion = 'Unknown';
double _random = 0xFFFFFFFF;
@override
void initState() {
super.initState();
initPlatformState();
//再次加载random
Timer.periodic(Duration(seconds: 3), (it){
initRandom();
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await FlutterPlugin.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
Future initRandom() async {
_random = await FlutterPlugin.randomCode;
setState(() {
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\nRandom:$_random'),
),
),
);
}
}

效果如图:

《Flutter入门——Flutter功能概览》

3、Flutter Package

Flutter Package 只是单纯的 flutter 包,我们在其中可以创建一个通用的 widget ,或者当做一个工具包等等,相当于一个弱化版的 Flutter Plugin。

创建过程不必多说,代码结构如图所示:

《Flutter入门——Flutter功能概览》

只需要在 lib目录 中编写公共的widget或者通用的逻辑方法即可。

4、Flutter Module

在继续往下介绍之前,可以先了解一下大致的flutter module 应用场景。

目前现有的应用,基本都已经成型,并且由于flutter 还并未完全成熟,因此如果使用的话,最多也只是替换现有项目部分内容当做一个Flutter模块。

Flutter 模块的创建需要遵循一定的规则,我们需要在项目的同级目录建立一个Flutter Module,然后有两种方式在原生代码中引入 Flutter (以Android 项目为例)

  1. 将Flutter当成一个 View 或者Fragment,并入到现有的Activity类中。
  2. 创建FlutterActivity 的实现类。

两者我更推崇后一个,因为后一个可以避免去处理多余的一些事件,比如返回键逻辑等等。

如果想以View 或者 Fragment 的方式引入 Flutter,可以参考这个博客完成:Android原生项目集成Flutter Module

当然这个博客都需要先看一下,里面包含了针对Android 的 build.gradle 以及 settings.gradle 的修改部分。这个是都需要配置的

如果以FlutterActivity 的形式引入Flutter,首先创建Flutter Module的过程都是一样的(都需要在原生项目同级目录下):

《Flutter入门——Flutter功能概览》

和一般的Flutter项目仅有微小的不同,就是在 pubspec.yaml中,会指明本项目为一个 附属module。

然后依照教程,使用AS在另一个窗口打开原生Android项目,在安卓项目的 settings.gradle中添加如下代码:

setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'gft_flutter_module/.android/include_flutter.groovy'
))

在 安卓项目主modulebuild.gradle文件中添加如下依赖:

dependencies {
// ... //flutter - module
implementation project(':flutter')
// ...
}

然后创建一个 FlutterActivity 的子类:

class FlutterContainerActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
companion object {
/** * 进入flutter时,可提供默认的路由 */
fun makeIntent(context: Context, routePage: String?): Intent {
var _routePage = routePage
if (_routePage == null || _routePage == "") {
_routePage = "/"
}
val intent = Intent(context, FlutterContainerActivity::class.java)
intent.action = Intent.ACTION_RUN
intent.putExtra("route", _routePage)
return intent
}
}
}

别忘了,该Acitivity 时需要 在 AndroidManifest 注册的 。

然后我们需要进入Flutter 模块功能界面时时,直接调用如下代码即可:

startActivity(FlutterContainerActivity.makeIntent(baseActivity, "/"))

这里展示一下使用Flutter模块效果图,开始是原生界面,然后点击进入的就是FlutterContainerActivity界面,两次进入传了不同的路由,因此显示了不同的Flutter界面:

《Flutter入门——Flutter功能概览》

当然,很多情况下,我们在引入module时,flutter中代码逻辑可能需要调用 原生代码,此时,可以直接修改一下FlutterContainerActivity代码:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
registerWith(flutterView.pluginRegistry.registrarFor("***.***.***"))
}

注:***代替的字符串部分只要使用唯一标识就行,一般可以用项目包名

在 onCreate 方法中,最后添加了一行插件注入的代码;registerWith方法是静态导入的,源码在插件类中:

/** * Created on 2019/4/26 18:32 * function : 定义的 flutter 和 android 交互监听 * * @author mnlin */
class UsdpBridgePlugin : MethodChannel.MethodCallHandler {
override fun onMethodCall(methodCall: MethodCall, result: MethodChannel.Result) {
println("flutter在调用android端的方法: ${methodCall.arguments} +++ ${methodCall.arguments::class.java}")
when (methodCall.method) {
"getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
"changeLocaleLanguage" means "修改语言环境" ->
//...
"changeThemeMode" means "模式切换" ->
//...
else -> result.notImplemented()
}
}
}
/** * 注册插件回调 */
fun registerWith(registrar: PluginRegistry.Registrar) {
MethodChannel(registrar.messenger(), "***").setMethodCallHandler(UsdpBridgePlugin())
}

注:***代替的字符串须要和Flutter中指定Channel的字符串相同,这样才可以互相调用。如果忘了是哪个字符串,可以参考博客前面创建 Flutter Plugin的部分,在Flutter插件类中代码处static const MethodChannel _channel = const MethodChannel('***');传入的字符串。

当然,若还是不清楚原生项目和flutter-module如何交互,可以查看此博客:Flutter知识点: Flutter与原生(Android)的交互

最后一定别忘了,在原生项目的 Application类中 onCreate时,先把Flutter模块初始化了,保证Flutter 与 原生无缝切换界面:

//初始化flutter框架
FlutterMain.startInitialization(this);

以上简单讲述了 Flutter 的使用方式,其实主要关注两个就行:第一,创建flutter跨平台项目;第二,让Flutter可以与原生项目进行合并。

三、 flutter_web——向WEB端前进

既然Flutter已经做到了横跨Android 和 IOS 两大平台,那么能否把Web端包含在内呢?这样不就实现了前端的 统一么?

然而,可惜的是,Flutter 并没有这个功能。

不过解决问题的方式总比困难多一些,官方已经给出了解决方案,或者说是一个 超功能的库:flutter_web

实现Flutter 项目 向 web端的迁移 ,不得不说,这个想法很不错,dart语言的初衷就是为了替代 js ,虽然失败了,但至少有过丰富的失败经验,那么依据dart语言的flutter做这些工作时,至少不会再开头就碰到太多的难题,也不用担心 此种方案的可行性。

flutter_web的README很详细的说明了迁移需要做的工作,然而,实在是 不想看那么多的逻辑。

好在我们都使用的是AS,那我们直接看 AS如何一键操作就好了,何必那么麻烦。

然而,使用AS 发现还是有些问题,根本没办法创建web项目,因此我们改用 Intellij 开发工具。步骤在 readme中已经列出来,像这样:

  1. install the Flutter SDK
  2. set up your copy of IntelliJ or Android Studio
  3. configure IntelliJ or Android Studio to point to your local Flutter SDK
  4. create a new Dart project; note, for a Flutter for web app, you want to start from the Dart project wizard, not the Flutter project wizard
    from the Dart project wizard,
  5. select the ‘Flutter for web’ option for the application template
  6. create the project; pub get will be run automatically
  7. once the project is created, hit the run button on the main toolbar
  8. IntelliJ will use the webdev command-line tool to build and run your app; a new Chrome window should open, showing your running app

SDK在前面步骤已经下载过了,那么接下来我们就完成剩下步骤:

首先,打开intellij 的settings 配置,添加 Dart 和 Flutter 插件,没有插件,我们是没办法创建项目的。

然后按照如下图创建一个 flutter – web 项目:

《Flutter入门——Flutter功能概览》

接下来选择创建项目的类型一定不能出错:

《Flutter入门——Flutter功能概览》

指定一下项目名:

《Flutter入门——Flutter功能概览》

点击 finish 创建完成。

等待idea把需要的依赖下载完成后,点击配置一下浏览器(URL地址不要主动去更改了):

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

配置后点击三角启动图标,如果启动不起来,不要着急,把idea重启一下就可以了。

启动后网页会自动打开,然后显示出默认的界面:

《Flutter入门——Flutter功能概览》

现在回头我们再看一下flutter – web 的目录结构:

《Flutter入门——Flutter功能概览》

lib目录中存放的是移动端flutter代码。

web目录下包含两个文件,index.html是网页入口,web/main.dart可以理解为从 flutter 到 web 的一个过渡桥梁,代码很简单,就是在网页初始化完成后,启动真正显示的布局信息。

main() async {
await ui.webOnlyInitializePlatform();
app.main();
}

当然,从 flutter 的代码是不能直接迁移到 flutter-web 的,需要更改一小部分内容,具体逻辑在github的readme文档中已经进行了说明:

If you’d like to migrate existing Flutter code to run on the web preview, read the migration guide.

flutter-web的更新也类似于hot-reload,在项目中修改代码后,直接刷新一次网页就可以显示出最新效果。

调试开发完成后,我们还需要进行部署,这个时候,就需要主动调用命令了,我们在启动服务时,可以很清楚的看到这样的内容:

《Flutter入门——Flutter功能概览》

这里指明了 webdev 包所在的位置,在打正事环境包时,先关闭调试的服务器,执行以下代码即可:

E:\flutter_sdk\flutter\bin\cache\dart-sdk\bin\pub.bat global run webdev build

切记,webdev 包的路径每个设备可能不同,因此一定要查看清楚再调用命令。

执行完成后,项目目录下多出 了一个 :

《Flutter入门——Flutter功能概览》

这个 build 目录中内容就是我们需要的正事包。切记,这个包直接双击浏览器打开index.html 文件是不行的,必须要放到 http 服务器中,这个官方在 readme中也有说明:

This will create a build directory with index.html, main.dart.js and the rest of the files needed to run the application using a static HTTP server.

我们可以进行简单的测试,看这个正事包能否正常使用,为了简单起见,我们使用 node 搭建一个小型的服务器:

《Flutter入门——Flutter功能概览》

《Flutter入门——Flutter功能概览》

然后,我们把通过命令生成的 build 目录下所有的文件,都拷贝过来,放到 node 项目的 public 目录下:

《Flutter入门——Flutter功能概览》

点击上面的三角形运行标志启动http服务;然后在浏览器中输入地址(node服务器默认启动端口号为3000):

http://localhost:3000/

然后浏览器中就会显示 flutter 指定的界面:

《Flutter入门——Flutter功能概览》

目前 flutter_web大概只有2000多star,毕竟前端人员几乎都在使用vue,也没有 迁移转换使用dart 的必要性。

不过,将来的趋势肯定倾向于前端的大一统,相信随着google的大力推行,会有更多的人接触使用flutter。

参考资料主要来源:Flutter中文网


推荐阅读
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • React 小白初入门
    推荐学习:React官方文档:https:react.docschina.orgReact菜鸟教程:https:www.runoob.c ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了Flutter添加APP启动StoryView相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • 随着前端技术的发展,越来越多的开发者开始使用react、vue等web框架,但很少有人深入理解这些框架的源码。然而,这些框架底层都是由原生的javascript构建而成。对于初学前端的人来说,可能会认为javascript很容易上手,但实际上只是因为它被高度封装了。与能够使用封装类的人相比,能够理解框架原理的人则处于另一个层面。本文将深入剖析jquery源码,探寻框架底层的原理,帮助读者更好地理解web框架的运行机制。 ... [详细]
  • 本文介绍了自学Vue的第01天的内容,包括学习目标、学习资料的收集和学习方法的选择。作者解释了为什么要学习Vue以及选择Vue的原因,包括完善的中文文档、较低的学习曲线、使用人数众多等。作者还列举了自己选择的学习资料,包括全新vue2.5核心技术全方位讲解+实战精讲教程、全新vue2.5项目实战全家桶单页面仿京东电商等。最后,作者提出了学习方法,包括简单的入门课程和实战课程。 ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
author-avatar
育霖培伦861
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有