美文网首页React Native
ReactNative flex布局&es6

ReactNative flex布局&es6

作者: 游侠_6fb7 | 来源:发表于2020-04-16 08:30 被阅读0次

    一、ES6常用语法 & 新特性
    二、Flex布局 & 样式
    三、一般组件的使用

    ES6常用语法 & 新特性
    1. ECMAScript6(简称ES6)是 JavaScript 语言的下一代标准。在2015年6月正式发布,所以又称ES2015。(Babel:ES6->ES5转码器)

      let, const, class, extends, super, arrow functions, template string, destructuring assignment, default, rest arguments, promise, generators, proxy, export, import

    2. let、const、var

    function test() {
        if (bool) {
            var test = 'hello'
        } else {
            console.log(test) //undefined
        }
        //undefined
    }
    

    相当于:

    function test() {
        var test //变量提升
        if (bool) {
            test = 'hello'
        } else {
            console.log(test) //undefined
        }
        //undefined
    }
    

    变量提升带来了较大的迷惑性,ES6提供了块作用域let、const

    1. 问题:父块中已有有一个同名变量,但是函数内部也需要用同名变量?
    var name = 'Red'
    while (true) {
        let name = 'Blue'
        console.log(name) //Blue
    }
    console.log(name) //Red
    

    块级作用域指在一个函数内部、或一个代码块内部,即{}大括号内的代码块即为let和const的作用域

    console.log(num); //num is not defined 
    let num = 3;
    

    在某个作用域中,在let声明之前调用了let声明的变量,导致的问题就是由于Temporal Dead Zone(TDZ)的存在
    变量会在我们进入块作用域时就会创建,TDZ也是在这时候创建的,它保证该变量不许被访问,只有在代码运行到let声明所在位置时,这时候TDZ才会消失,访问限制才会取消,变量才可以被访问

    const

    1.const声明的变量在声明时必须赋值,否则会报错:SyntaxError, missing initializer
    2.const声明的变量不能再被赋予别的值。在严格模式下,试图改变const声明的变量会直接报错;在非严格模式下,改变被静默忽略
    3.通过const声明的变量值并非不可改变。使用const只是意味着,变量将始终指向相同的对象或初始的值(引用是不可变的,但是值并非不可变)

    下面的例子说明,虽然people的指向不可变,但是数组本身是可以被修改的。
    const people = ['China', 'USA']
    people.push('England')
    console.log(people) //['China', 'USA', 'England']

    class、extends、super

    JS本身就是面向对象的,ES6中提供的类实际上只是JS原型模式的包装。引入了class(类)的概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂

    class Human {
        constructor(name) { //构造方法,this关键字则代表实例对象
            this.name = name;
            //constructor内定义的方法和属性是实例对象自己的
            //而constructor外定义的方法和属性则是所有实例对象可以共享的
        }
    
        sleep() {
            console.log(this.name + " is sleeping");
        }
    }
    let man = new Human("James");
    man.sleep(); //James is sleeping
    
    class Boy extends Human {
        //通过extends关键字实现继承,继承了Human类的所有属性和方法
        constructor(name, age) {
            //super关键字,指代父类的实例(即父类的this对象)
            super()
            this.name = name;
            this.age = age;
        }
    
        info() {
            console.log(this.name + 'is ' + this.age + 'years old');
        }
    }
    let boy = new Boy('Love', '18');
    boy.sleep(); //Love is sleeping
    boy.info(); //Love is 18 years old
    

    子类必须在constructor方法中调用super方法,否则新建实例时会报错
    这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
    ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

    arrow functions

    JS中声明的普通函数,一般有函数名,一系列参数和函数体,如下:
    function name(parameters) {
    // function body
    }

    普通匿名函数则没有函数名,匿名函数通常会被赋值给一个变量/属性,有时候还会被直接调用:

    var example = function (parameters) {
        // function body
    }
    

    ES6提供了一种写匿名函数的新方法,即箭头函数。箭头函数不需要使用function关键字,其参数和函数体之间以=>相连接:

    var example = (parameters) => {
        // function body
    }
    

    箭头函数与匿名函数的区别:
    1.箭头函数不能被直接命名,不过允许它们赋值给一个变量;
    2.箭头函数不能用做构造函数,你不能对箭头函数使用new关键字;
    3.箭头函数也没有prototype属性;
    4.箭头函数绑定了词法作用域,不会修改this的指向

    class Human {
        constructor(name) {
            this.name = name;
        }
    
        sleep() {
            setTimeout(function () {
                console.log(this.name + " is sleeping");
            }, 1000)
        }
    }
    let man = new Human("James");
    man.sleep(); // is sleeping
    
    //将this传给self,再用self来指代this
    sleep() {
        var self = this;
        setTimeout(function () {
            console.log(self.name + " is sleeping");
        }, 1000)
    }
    
    //或bind(this)
    sleep() {
        setTimeout(function () {
            console.log(self.name + " is sleeping")
        }.bind(this), 1000)
    }
    

    使用箭头函数
    词法作用域:箭头函数的函数体内使用的this,arguments,super等都指向包含箭头函数的上下文,箭头函数本身不产生新的上下文。原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。

    var example = (parameters) => {
        // function body
    }
    

    当只有一个参数时,我们可以省略箭头函数参数两侧的括号:

    var double = value => {
        return value * 2
    }
    

    对只有单行表达式且,该表达式的值为返回值的箭头函数来说,表征函数体的{},可以省略,return关键字可以省略,会静默返回该单一表达式的值

    var double = (value) => value * 2
    

    合并使用

    var double = value => value * 2
    

    注意!
    箭头函数返回值为一个对象时,你需要用小括号括起你想返回的对象。否则,浏览器会把对象的{}解析为箭头函数函数体的开始和结束标记。正确的使用形式

    var objectFactory = () => ({ modular: 'es6' })
    
    template string

    模板字符串:ES6中允许使用反引号`来创建字符串,此种方法创建的字符串里面可以包含由符号与{}包裹的变量{vraible}

    let num = Math.random();
    console.log(` num is ${num}`);  //num is xx
    

    模板字符串中所有的空格、新行、缩进,都会原样输出在生成的字符串中

    destructuring assignment

    ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

    1.交换变量的值,不再需要中间变量

    let a = 1;
    let b = 2;
    [a, b] = [b, a];
    console.log(a, b);  //2 1
    

    2.提取JSON数据

    let jsonData = {
        id: 1,
        title: "OK",
        data: [5, 6]
    };
    let {id, title, data:number} = jsonData;
    console.log(id, title, number); //1, "OK", [5, 6]
    

    3.函数参数的定义

    //参数是一组有次序的值
    function f([x, y, z]) {
    ...
    }
    f([1, 2, 3]);
    
    //参数是一组无次序的值
    function f({x, y, z}) {
    ...
    }
    f({z: 3, y: 2, x: 1});
    
    default默认值

    default默认值可以在定义函数的时候指定参数的默认值,而不用像以前那样通过逻辑或操作符来达到目的了。

    //传统指定默认参数
    function say1(name) {
        var name = name || 'James';
        console.log( 'Hello ' + name );
    }
    
    //ES6默认参数
    function say2(name='Love') {
        console.log(`Hello ${name}`);
    }
    say1();      //Hello James
    say1('JR');  //Hello JR
    say2();      //Hello Love
    say2('TT');  //Hello TT
    

    rest参数
    1.rest参数只包括那些没有给出名称的参数;
    2.rest参数是Array的实例,可以直接应用sort, map, forEach, pop等方法;
    3.rest参数之后不能再有其它参数(即,只能是最后一个参数);
    4.函数的length属性,不包括rest参数;

    function fn(x, y, ...rest){
        console.log(rest)
    }
    fn(1, "cat", "dog", 2); //["dog", 2]
    console.log(fn.length); //2
    
    promise

    在promise之前代码过多的回调或者嵌套,可读性差、耦合度高、扩展性低。通过Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的方式来编写异步代码,保存线性的代码逻辑,极大的降低了代码耦合性而提高了程序的可扩展性。

    即用同步的方式去写异步代码。Promise/A+规范, 规定Promise对象是一个有限状态机。它三个状态:
    pending(执行中)
    Resolved(已完成)
    Rejected(已失败)
    其中pending为初始状态,Resolved和rejected为结束状态(表示promise的生命周期已结束)

    let val = 1;
    //假设step1, step2, step3都是数据库的异步操作
    //每个步骤都有对应的失败和成功处理回调
    //step1、step2、step3必须按顺序执行
    function step1(resolve, reject) {
        console.log('步骤一:执行');
        if (val >= 1) {
            resolve('Hello I am No.1');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    function step2(resolve, reject) {
        console.log('步骤二:执行');
        if (val === 1) {
            resolve('Hello I am No.2');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    function step3(resolve, reject) {
        console.log('步骤三:执行');
        if (val === 1) {
            resolve('Hello I am No.3');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    new Promise(step1).then(function(val){
        console.info(val);
        return new Promise(step2);
    }).then(function(val){
        console.info(val);
        return new Promise(step3);
    }).then(function(val){
        console.info(val);
        return val;
    }).then(function(val){
        console.info(val);
        return val;
    });
    

    // 执行之后将会打印
    步骤一:执行
    Hello I am No.1
    步骤二:执行
    Hello I am No.2
    步骤三:执行
    Hello I am No.3
    Hello I am No.3

    关键点:
    在Promise定义时,函数已经执行了;Promise构造函数只接受一个参数,即带有异步逻辑的函数。这个函数在new Promise 时已经执行了。只不过在没有调用then之前不会resolve或reject。

    在then方法中通常传递两个参数,一个resolve函数,一个reject函数。reject就是出错的时候运行的函数。resolve 函数必须返回一个值才能把链式调用进行下去。
    1.resolve返回一个新Promise:返回一个新Promise之后再调用的then就是新Promise中的逻辑了。
    2.resolve 返回一个值:返回一个值会传递到下一个then的resolve方法参数中

    generators

    generator函数跟普通函数的写法有非常大的区别:
    1.function关键字与函数名之间有一个*
    2.函数体内部使用yield语句,定义不同的内部状态

    function* f() {
        yield 'a';
        yield 'b';
        yield 'c';
        return 'ending';
    }
    
    let fn = f();
    console.log(fn.next()); // { value: 'a', done: false }
    console.log(fn.next()); // { value: 'b', done: false }
    console.log(fn.next()); // { value: 'c', done: false }
    console.log(fn.next()); // { value: 'ending', done: true }
    

    异步操作的同步化写法
    generator函数的暂停执行的效果,意味着可以把异步操作写在yield语句里面,等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了,因为异步操作的后续操作可以放在yield语句下面,反正要等到调用next方法时再执行。所以,generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数

    proxy代理

    proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。

    //定义被监听的目标对象
    let man = { name: 'James', age: 18 };
    //定义处理程序
    let handle = {
        set(receiver, property, value) {
            console.log(property, 'is changed to', value);
            receiver[property] = value;
        }
    };
    //创建代理以进行侦听
    man = new Proxy(man, handle);
    //做一些改动来触发代理
    man.age = 22;  //age is change to 22
    man.name = "Love";  //name is change to Love
    
    export、import

    export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口;
    import用于在一个模块中加载另一个含有export接口的模块。

    导出一组对象。导出模块文件app.js:

    class Human{
        constructor(name) {
            this.name = name;
        }
        sleep() {
            console.log(this.name + " is sleeping");
        }
    }
    function walk() {
        console.log('i am walking');
    }
    function play() {
        console.log('i am playing');
    }
    export { Human, walk }
    

    模块导出了两个对象:Human类和walk函数,能被其他文件使用。而play函数没有导出,为此模块私有,不能被其他文件使用。

    main.js导入app.js模块
    import { Human, walk } from 'app.js';

    Default导出
    使用关键字default,可将对象标注为default对象导出。default关键字在每一个模块中只能使用一次。
    ... //类,函数等
    export default App;
    main.js导入app.js模块
    import App from 'app.js';

    Flex布局

    Flex是Flexible Box的缩写,意为"弹性盒布局",用来为盒状模型提供最大的灵活性。采用Flex布局的元素,称为Flex container,它的所有子元素自动成为容器成员,称为Flex item。


    image.png

    1.容器默认存在两根轴:主轴(main axis)和交叉轴(cross axis);
    2.主轴的开始位置叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end;
    3.单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size;
    4.项目默认沿主轴排列。

    container属性

    flexDirection enum('row','column')
    flexDirection决定主轴的方向,如果取值为row,那么Main Axis为横轴;若取值为column,Main Axis则为竖轴。
    flexWrap enum('wrap','nowrap')

    justifyContent
    image.png
    alignItems
    image.png
    item属性

    flex enum(number)
    定义剩余空间的比例。flex=0的项目占用空间仅为内容所需空间,flex=1的项目会占据其余所有空间。
    alignSelf enum('auto','flex-start','flex-end','center','stretch')
    alignSelf定义Item自己在Container中的对齐方式。

    layout的其它属性

    /node_modules/react-native/Libraries/StyleSheet/LayoutPropTypes.js


    image.png

    react的默认位置方式是relative,item是一个接一个排列下去的;absolute为绝对布局,一般会与left和top属性一起使用(有时候我们需要实现某些项目重叠起来,absolute属性就能发挥作用了)

    布局尺寸说明

    React Native的宽高是不需要带单位的,width,height,padding,margin的赋值都直接是数字的,当设定width:10,在iOS的话就是设置了10pt宽度,而在Android上面是10dp

    样式说明

    React Native没有实现css来渲染样式,而是使用JavaScript声明样式
    1.它属性的名称和css上的不一样;
    2.它支持的属性比较少;
    3.它支持的属性取值也比较少
    声明:

    var styles = StyleSheet.create({
        container: {
            flexDirection: 'row',
            flexWrap: 'wrap',
            justifyContent: 'center',
            alignItems: 'center',
            flex: 1,
            backgroundColor: '#ffffff',
        },
        item: {
            width: 75,
            height: 75,
            color: '#ffffff',
            backgroundColor: '#666666',
            margin: 10,
        }
    });
    

    使用:

    <View style={styles.container}>
        <Text style={styles.item}>
            1
        </Text>
        <Text style={styles.item}>
            2
        </Text>
    </View>
    

    相关文章

      网友评论

        本文标题:ReactNative flex布局&es6

        本文链接:https://www.haomeiwen.com/subject/xrdkvhtx.html