Giter Site home page Giter Site logo

blog's People

Watchers

 avatar  avatar

blog's Issues

JavaScript垃圾回收

在日常前端开发过程中我们比较少的接触到这个词垃圾回收,因为JavaScript具有自动垃圾回收机制,开发者并不需要着重关心变量的申请和回收,如果之前接触过原生开发可能会大概知道OC中有alloc和release,即自己做内存管理及释放。但是当我们的产品对性能有要求的时候,我们就要关注内存的管理了。

什么是垃圾回收机制

看这个名词可能会理解为:找到并且清除垃圾。但是JavaScript在现代浏览器上所用到的机制事实上却恰恰相反。如MDN 上所述:

假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。
垃圾回收器将定期从根开始,找所有从根开始引用的对象,
然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。

这个算法比前一个要好,因为“有零引用的对象”总是不可获得的,但是相反却不一定,参考“循环引用”。

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。
所有对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义

JavaScript垃圾回收会跟踪所有仍在使用的对象,然后将剩余的对象标记为垃圾。垃圾回收器会销毁标记为垃圾的值并回收他们所占用的内存空间。只有当变量没有被引用,那么它们就会被删除。

如果我们代码使用姿势不对,往往会导致自动垃圾回收机制无法正常释放已经不再使用的内存,造成内存泄露等性能问题。

常见内存泄露

全局变量

从MDN的解释中可以看出全局变量是不会被回收的,当我们无意中产生了全局变量时,其实就造成了内存泄露了。

var a = () => {
  globalVar = 1
  return "2"
}

定时器

timer是个全局变量,并且timer始终没有被销毁,test每次都不会被回收。

var n = 0
var timer = null
function test() {
  n++
  console.log(n)
  if (n === 5) {
    return
  }
  timer = setTimeout(test, 1000)
}

test()

闭包

这个闭包造成内存泄露我觉得可以商榷,正是因为我想让变量一直保存在内存中,所以才使用闭包,并不能不推荐使用。

结语

这里我只是做一个简单的垃圾回收的介绍及常见的我们在代码中无意中会引发内存泄露问题的小总结。关于更详细的内容及查看内存泄露的工具可以参考阮老师

😂

GraphQL 入门

1.介绍

我们在做业务中后台的前后端分离实践中,一直享受着Restful接口带来的便利,前端对所有的数据(资源)进行GET/POST/PUT/DELETE操作。如果一个Restful接口不能解决,那就两个。但实际上,前面这句话正是GraphQL所要解决的突出问题:
Restful接口返回的数据是固定的,如果我们还要取另外一个模型的数据, 大部分后端就会给我们开另外一个Restful接口了。
这种方式没啥问题,但不够优雅及不能快速迭代。例如:一个有推荐系统的简单的商品详情页会调用商品详情(getItemInfo)和推荐商品列表(getRecommendItemList)两个GET接口。

官网对于GraphQL的解释:
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。
通俗点来说就是:
一个GraphQL接口,前端来定义接口返回的数据结构,后端会根据前端传过来的数据结构的定义,返回前端所需要的数据。给客户端自由筛选获取服务端事先定义好的数据,提高了交互接口的灵活性。

Preview Screenshot

2.基础用法

官网提供demo可以看一下简单用法。

可以总结为两句话:1.构建schema,定义查询的语句(方法)和类型。2.定义查询所对应的resolver,即查询对应的处理器。
我们以一个有推荐系统的简单的商品详情页来做详细示例。

类型

类型一般有

  • Int:有符号 32 位整数。
  • Float:有符号双精度浮点值。
  • String:UTF‐8 字符序列。
  • Boolean:true 或者 false。
  • 枚举类型
  • 列表和非空
  • 接口(一个接口是一个抽象类型,它包含某些字段,而对象类型必须包含这些字段,才能算实现了这个接口)

定义shema

GraphQL 通过 type 关键字来定义一个类型,即定义一个结构描述,我们定义一个简单的商品详情:

  type Item {
    itemId: Int
    itemName: String
    mainImage: String
    price: String
    unit: String
    shopId: String
    shopName: String
    lowPrice: String
    highPrice: String
  }

再定义一个简单的商品推荐列表:

  type RecommendItem {
    itemId: Int
    itemName: String
    mainImage: String
    price: String
    unit: String
  }

我们通过中括号 [] 来指定列表, 对于默认类型Query我们可以定义查询的语句和类型为:

  type Query {
    getItemInfo: Item
    getRecommendItemList(id: Int): [RecommendItem]
  }

提供resolver函数

resolver函数就是正常的js函数,函数体里可以执行正常的数据库操作,返回结构需要按照上文定义的类型来处理。

var root = {
  getRecommendItemList: ({ id }) => {
    const data = [
      {
        itemId: 124,
        itemName: '91号汽油-1',
        mainImage: 'http://www.terminus.com',
        price: '1234',
        unit: '吨',
        getComment: getComment(id)
      },
      {
        itemId: 125,
        itemName: '91号汽油-2',
        mainImage: 'http://www.terminus.com',
        price: '1234',
        unit: '吨',
        getComment: getComment(id)
      },
    ]
    return data.filter(({ itemId }) => itemId === id)
  },
}

更新操作

对于变更(mutation)操作,有时候需要传递一整个对象作为新建对象,输入对象看上去和常规对象一模一样,除了关键字是 input 而不是 type。

  input ItemInput {
    itemName: String
    price: String
    unit: String
  }

3.构造类型

对于日常开发来说,不太可能直接用字符串定义这么多类型(不能模块化,错误不好处理问题等)。GraphQL也提供了构造函数构建Schema:GraphQLSchema, GraphQLObjectType,GraphQLInt, GraphQLFloat等等。基本用法是实例化这些类型构造函数,传入name,fields等参数。
简单的商品详情:

var MyItemType = new GraphQLObjectType({
  name: 'MyItem',
  fields: {
    itemId: {
      type: GraphQLInt,
    },
    itemName: {
      type: GraphQLString,
    }
    ...
  }
})

其余的可以参照详细代码

4.客户端调用

之前我们一直在服务端做处理,具体客户端如何请求到数据?其实并不复杂,其实就是把我们所需要的结构类型通过http请求发到后端,就可以得到相应的数据了。官网的示例:

fetch('/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: JSON.stringify({query: "{ hello }"})
})
  .then(r => r.json())
  .then(data => console.log('data returned:', data));

简单来说,就是把结构类型传入body中。

我们举一个相对复杂的例子:

const sql2 = `query test($id: Int) {
  getRecommendItemList(id: $id) {
    itemId
    itemName
    mainImage
  }
  getItemInfo 
      {
        itemId
        itemName
        mainImage
      }
}

query test2($id: Int) {
  getRecommendItemList(id: $id) {
    mainImage
  }
  getItemInfo 
      {
        mainImage
      }
}`

这个请求query里有两个操作,一个是test操作(返回结构内容比较多),一个是test2操作(返回结构内容较少),直接把这段字符串发送给GraphQL是会报错的,因为需要指定操作即operationName。详细可以调用一下代码测试

对于更新操作,和查询大同小异

    const sql3 = `mutation test($item: ItemInput ) {
     updateItemInfo(item: $item) {
       itemId
       itemName
       mainImage
       price
       shopId
       shopName
     }
   }

5.用户信息及文件处理

用户信息

GraphQL会默认把request挂载在context上,也就是resolve的第三个参数。可以通过context来做用户登录和权限的处理。

var postType = new GraphQLObjectType({
  name: 'Post',
  fields: {
    body: {
      type: GraphQLString,
      resolve: (post, args, context, { rootValue }) => {
        // 只有当用户是帖子的作者时才返回帖子正文
        if (context.user && (context.user.id === post.authorId)) {
          return post.body;
        }
        return null;
      }
    }
  }
});

文件处理

GraphQL并不想解决所有接口,上传接口还是推荐用restful接口。但是GraphQL并不是不能处理。
对于文件处理,我以一个简单的demo做说明。即query的数据类型单独放一个字段,通过中间件处理文件数据,并且将GraphQL接口所需要的入参重新赋予request.body。

DSL是什么

前言

之前同学分享过编写babel插件里涉及到了DSL,这里对DSL做一个相对全面的认识。即什么是DSL,为什么需要DSL。

什么是DSL

维基百科中对DSL(特定领域语言)的定义是

专注于某个应用程序领域的计算机语言。又译作领域专用语言

简单来说就是在某一特定宿主环境下,才能应用的语言。比如说浏览器中使用的HTML,CSS,再比如我们定义的模板语言Handlebars,都属于在某一特定宿主环境下应用的语言,虽然这些宿主的层次级别并不同。甚至我们在开发业务过程中,抽取出来的特定的配置文件,某种程度上也可以称作DSL。
与特定领域语言相对应的语言则是通用型的编程语言,比如说C, C++等等。

为什么要DSL

以下有段代码:

000000000001

作为人类可以理解这段代码吗?答案显而易见:什么JB玩意儿。但是对于计算机来说,这对01,简直太够意思了,太容易理解了:地址为 1 的存储器。

这其实就是需要DSL的原因,抽象层次越低对机器越友好,对人类理解却更难,我们按照抽象层次给编程语言划分一下(从低到高):机器语言,汇编语言,高级语言。而DSL就是在高级语言之上的,即抽象层次更高级别的语言。DSL主要的目标是为了能够以更简单、更容易理解的方式完成我们的业务需求。
举一个不够恰当但是易于理解的例子。给DIV中增加一个INPUT。我们用高级语言JavaScript会这么写:

var divEl=document.createElement("div")
var inpurEl=document.createElement("input")
div.appendChild(inpurEl)

而我们用浏览器DSL 即HTML来描述则是:

<div><input/></div>

对于一个没接触过前端的人来说,我坚信,下面的代码他更容易理解一些。

实现DSL

实现DSL很简单,就两句话:

  • 设计语法和语义,定义 DSL 中的元素是什么(比如ES6)
  • 实现 parser,对 DSL 解析,最终通过解释器(对前端常用的es6来说可能就是babel)来执行

比如说,我们定义了es6种的箭头函数的语法 =>, 而 => 会被babel这个解释器根据设计的语法和语义,来进行语法分析,词法分析最终会转译为es5的函数定义语法。
比如:

var test = function (){
  var myTest = ()=>{
    this.num = 1
  }
}

会被转译为:

"use strict";

var test = function test() {
  var _this = this;

  var myTest = function myTest() {
    _this.num = 1;
  };
};

对于抽象语法数这块的内容,可以参考之前同学分享的内容或者在网上搜索AST相关的内容。

ReactNative原生Android UI组件拓展开发&发布

说明: 本文档用于指导前端React Native的原生Android UI组件开发&发布,如需开发其他其他框架应用,不适用本文档

React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件。
而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。
幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。

RN官网上这么描述拓展原生UI组件开发封装,真的是日了狗,我在实践中遇到了不少问题,官网文档有些甚至是错误的,废话不多说,以下是依照官网示例中的imageview所做的实践教程。

1.原生组件环境

新建RN项目

按照官网步骤新建一个RN项目

$ react-native init example

新建好之后,使用Android Studio打开RN项目中android文件夹下的android工程

新建Android库

使用Android Studio新建Module,即File->New->New Module->Android Library。
androidlibrary

我们给静态库取名为NativeImageExample。

在Android/app中修改build.gradle,在dependencies中添加

compile project(':nativeimageexample')

这样我们的Android库能够关联到app工程下。
为了开发Android库,还需要其依赖react native,nativeimageexample/修改build.gradle,在dependencies中添加

compile "com.facebook.react:react-native:+"  // From node_modules

2.开发原生组件

在.../nativeimageexample/src/main/java/com/example/nativeimageexample文件夹下新建类NativeImageExampleManager,该类继承自类SimpleViewManager,
newclass
nativeimageexamplemanager

这个类必须实现两个方法,一个是覆写getName方法,它返回一个字符串名字,在JS中我们就使用这个名字调用这个模块;另外一个是构造方法NativeImageExampleManager,部分代码如下:

package com.example.nativeimageexample;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.views.image.ReactImageView;
import android.support.annotation.Nullable;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.views.image.ImageResizeMode;


public class NativeImageExampleManager extends SimpleViewManager<ReactImageView> {
    public static final String REACT_CLASS = "RCTImageView";
    public NativeImageExampleManager(Object mCallerContext) {
        this.mCallerContext = mCallerContext;
    }
    @Override
    public String getName() {
        return REACT_CLASS;
    }
}

注意⚠️:此时Android Studio可能会提示错误:

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:11:7-34
  	is also present at [example:nativeimageexample:unspecified] AndroidManifest.xml:12:9-35 value=(true).
  	Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-24:19 to override.

这个解决办法是将.../nativeimageexample/src/main/AndroidManifest.xml中的allowBackup设置为false。
此时我们还不能访问此module,还需要创建实现ReactPackage的接口(interfaces)的NativeImageExamplePackage类。代码:
nativeimageexamplepackage

package com.example.nativeimageexample;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class NativeImageExamplePackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        List<ViewManager> viewManagers = Arrays.<ViewManager>asList(
                new NativeImageExampleManager(reactContext)
        );
        return viewManagers;
    }
}

修改.../android/app/src/main/java/com/example/MainApplication.java
文件中的getPackages方法。

import com.example.nativeimageexample.NativeImageExamplePackage;
...

public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          	new NativeImageExamplePackage()
      );
    }
}

这个时候我们运行命令:

$ react-native run-android

你可能会惊喜的发现报错了❌

Error retrieving parent for item: 
No resource found that matches the given name 'android:
TextAppearance.Material.Widget.Button.Borderless.Colored'.
...

我们可以通过修改.../android/nativeimageexample/build.gradle

android {
    compileSdkVersion 23
    buildToolsVersion '26.0.1'

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
        ...
    }
}
dependencies {
...
//    compile 'com.android.support:appcompat-v7:26.+'
    compile "com.android.support:appcompat-v7:23.0.1"
...
}

这个方法不一定对,是我自己猜测之后修改的。😅

这个时候,我们在js中可以访问一下我们的代码:

import { requireNativeComponent} from 'react-native';
...
let NativeUIModuleExample = requireNativeComponent('RCTImageView', null);
...
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <NativeUIModuleExample src={[{uri:'http://f.named.cn/f/45de9752d88841c87da0f23f8a798a4c.jpg'}]} style={styles.test}/>
        <Text style={styles.instructions}>
          To get started, edit App.js
        </Text>
        <Text style={styles.instructions}>
          {instructions}
        </Text>
      </View>
    );
  }
}
...

注意给样式加上宽高。

end

3.发布

接下来就是我们熟悉的发布npm了

在github上创建一个仓库react-native-NativeImageModuleExample,clone到本地创建android文件夹

$ git clone [email protected]:necfol/react-native-NativeImageModuleExample.git
$ cd react-native-NativeImageModuleExample
$ mkdir android

拷贝我们之前创建的.../android/nativeimageexample文件夹下的所有内容

$ cp -R ../../../../androidtest/example/android/nativeimageexample/* ~Necfol/focus/newcrovapp/androidtest/npm/react-native-NativeImageModuleExample/android

在react-native-NativeImageModuleExample目录下创建一个index.js,它是整个原生模块的入口,我们这里只是将原生进行导出

import {
    requireNativeComponent
  } from 'react-native';
  var RCTImageView = requireNativeComponent('RCTImageView', null);
  module.exports = RCTImageView;

在react-native-NativeImageModuleExample文件夹下运行命令

$ npm init

输入相应的信息,package.json就创建完成了。

{
  "name": "react-native-nativeimagemoduleexample",
  "version": "1.0.0",
  "description": "my Android RN native module demo",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/necfol/react-native-NativeImageModuleExample.git"
  },
  "author": "Necfol",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/necfol/react-native-NativeImageModuleExample/issues"
  },
  "homepage": "https://github.com/necfol/react-native-NativeImageModuleExample#readme"
}

接下来我们就可以

npm publish

4.使用

新建一个RN项目,依次运行:

$ npm install --save react-native-nativeimagemoduleexample
$ npm install
$ react-native link

在App.js中新增代码:

import NativeImageModule from 'react-native-nativeimagemoduleexample';
<!--在render中-->
<NativeImageModule src={[{uri:'http://f.named.cn/f/45de9752d88841c87da0f23f8a798a4c.jpg'}]} style={styles.image}/>

运行:

$ react-native run-android

end2

Demo可参考示例

官方文档中还有属性,事件之类用法,暂不做介绍。

ReactNative原生iOSUI组件拓展开发&发布

说明: 本文档用于指导前端React Native的原生iOSUI组件开发&发布,如需开发其他其他框架应用,不适用本文档

React Native已经封装了大部分最常见的组件,譬如ScrollView和TextInput,但不可能封装全部组件。
而且,说不定你曾经为自己以前的App还封装过一些组件,React Native肯定没法包含它们。
幸运的是,在React Naitve应用程序中封装和植入已有的组件非常简单。

RN官网上这么描述拓展原生UI组件开发封装,真的是日了狗,我在实践中遇到了不少问题,官网文档步骤并不全面,废话不多说,以下是依照官网示例中的mapview所做的实践教程。

1.原生组件环境

新建静态库

使用xcode新建静态库,即File->new->project->Cocoa Touch Static Library。
staticlibrary

我们给静态库取名为NativeUIExample。

新建RN项目

按照官网步骤新建一个RN项目

$ react native init Dialogtest

新建好之后,打开RN项目中ios文件夹下的iOS工程

模拟npm link

如果单独在项目外新建一个npm包,通过link来配置本地组件环境的话,我们新建的npm包需要依赖的环境和新建的RN项目基本相同,
并且我们开发静态库设置搜索路径Header Search Paths时与正式打包之后的路径不同,远不如模拟npm link方便。

在RN项目的node_modules文件夹下创建新的文件夹react-native-NativeUIExample,在新文件夹下新建ios文件夹

$ cd Dialogtest/node_modules
$ mkdir react-native-NativeUIExample
$ cd react-native-NativeUIExample
$ mkdir ios

将之前建好的静态库的内容copy到ios文件夹下
dir

用xcode打开react-native-NativeUIExample/ios下的ios工程,在targets->Build Settings下找到Header Search Paths,设置其值为

$(SRCROOT)/../../react-native/React

并且选择设置recursive
recursive

将react-native-NativeUIExample文件夹下的NativeUIExample工程拖到RN项目的iOS工程中的Library中

library

选中 TARGETS => Dialogtest => Build Phases => Link Binary With Libraries,添加libNativeUIExample.a这个静态库(注意:如果找不到这个静态库,就cmd+k,clean一下,还不行就重启xcode,多试几次就行😊)

linkbinarywithlibraries

现在我们已经把环境搭建好了,模拟了npm link了

2.开发原生组件

这里我们只是将官网的mapview组件示例展现部分开发一下,其余的开发组件相关内容可以参考官网

  • 在Dialogtest iOS工程Libraries的NativeUIExample.m中,添加RCT_EXPORT_MODULE(NativeUIExample)标记宏
  • 实现-(UIView *)view方法

RCT_EXPORT_MODULE(NativeUIExample) 括号里即是暴露给js使用的组件名

//
//  NativeUIExample.m
//  NativeUIExample
//

#import <MapKit/MapKit.h>

#import "RCTViewManager.h"

@interface NativeUIExample : RCTViewManager
@end

@implementation NativeUIExample

RCT_EXPORT_MODULE(NativeUIExample)

- (UIView *)view
{
    return [[MKMapView alloc] init];
}

@end

现在我们原生组件已经开发完成了,那么我们Javascript如何调用呢?

在我们RN项目App.js文件中编写代码

import {
  Platform,
  StyleSheet,
  Text,
  View,
  requireNativeComponent
} from 'react-native';
let NativeUIExample = requireNativeComponent('NativeUIExample', null);
//...其余代码
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <NativeUIExample style={styles.test}/>
        <Text style={styles.instructions}>
          To get started, edit App.js
        </Text>
        <Text style={styles.instructions}>
          {instructions}
        </Text>
      </View>
    );
  }
}

注意:我们需要给NativeUIExample这个组件加上宽高,否则并不能显示地图

在我们的RN项目中运行命令

$ react-native run-ios

此刻即可看到原生组件被我们通过js的形式显示出来了。

end

3.发布

接下来就是我们熟悉的发布npm了

在github上创建一个仓库react-native-NativeUIExample,然后关联到我们前面创建的react-native-NativeUIExample目录

$ cd Dialogtest/node_modules/react-native-NativeUIExample
$ git init .
$ git remote add origin [email protected]:necfol/react-native-NativeUIExample.git

在react-native-NativeUIExample目录下创建一个index.js,它是整个原生模块的入口,我们这里只是将原生进行导出

import {
  requireNativeComponent
} from 'react-native';
var NativeUIExample = requireNativeComponent('NativeUIExample', null);
module.exports = NativeUIExample;

在react-native-NativeUIExample文件夹下运行命令

$ npm init

输入相应的信息,package.json就创建完成了。

{
  "name": "react-native-nativeuiexample",
  "version": "1.0.0",
  "description": "my RN native module demo",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/necfol/react-native-NativeUIExample.git"
  },
  "author": "Necfol",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/necfol/react-native-NativeUIExample/issues"
  },
  "homepage": "https://github.com/necfol/react-native-NativeUIExample#readme"
}

接下来我们就可以

npm publish

4.使用

新建一个RN项目,依次运行:

$ npm install --save react-native-nativeuiexample
$ npm install
$ react-native link

在App.js中新增代码:

import NativeUIExample from 'react-native-nativeuiexample';
<!--在render中-->
<NativeUIExample style={styles.test} />

运行:

$ react-native run-ios

Demo可参考示例

官方文档中还有属性,事件之类用法,暂不做介绍。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.