React(二):jsx事件绑定、条件渲染、列表渲染、jsx的本质、购物车案例

news2024/11/16 12:02:53

React(二)

  • 一、jsx事件绑定
    • 1.this的绑定方式
    • 2.jsx中绑定this的三种方式
    • 3.事件对象和传参
      • (1)事件对象怎么传
      • (2)其他参数怎么传?
  • 二、条件渲染
    • 1.直接if-else
    • 2.三元表达式
    • 3.利用逻辑中断
    • 4.案例练习
    • 5.模拟v-show的实现
  • 三、列表渲染
  • 四、jsx的本质
    • 1.babel如何转换
    • 2.虚拟DOM的生成
  • 五、购物车案例
    • 1.总价的计算
    • 2.点击加号和减号
    • 3.删除某行数据
    • 4.没有数据时给用户提示

一、jsx事件绑定

1.this的绑定方式

1、默认绑定,独立执行:fun(),一般绑定window,严格模式下undefined
2、隐式绑定:被一个对象执行:obj.fun() => obj
3、显式绑定:call / apply / bind,fun.bind('aaa) => String('aaa')
4、new绑定:new Fun(),创建一个实例,this指向实例

还是之前的一些知识点,看一下下面的代码:

const obj = {
    foo: () => {
        console.log(this);
    }
}
const obj2 = {
    onclick : obj.foo
}
obj2.onclick(); //window

这种情况我们是把obj里面的方法赋值给了另一个变量,这样我们调用的话相当于进行了默认绑定,如果上面这段不好理解,那么看看下面的:

const obj = {
    foo: () => {
        console.log(this);
    }
}
let fun = obj.foo
fun(); //window

2.jsx中绑定this的三种方式

以下面这段代码为例:

1、显式绑定this,之前我们了解的都是直接把函数的地址给到点击事件,但是由于es6中的函数默认开启严格模式,this指向undefined,需要手动利用bind改变this指向

2、利用箭头函数找到this。fun2可以以一个变量的形式保存一个箭头函数(在es6中可以省略constructor直接给变量赋值)。如果我们把一个箭头函数的地址绑定给点击事件,那么就不会有this指向问题。(箭头函数没有自己的this,会向上层作用域查找,而上层作用域是类的作用域,指向的当然是类的实例)

3、目前最常用的,直接写箭头函数,点击时触发一个箭头函数的回调,箭头函数可以调用另外一个函数,这样的话就是一个隐式绑定(this.fun3(),那么fun3里的this当然指向的也是类的实例),解决了this指向的问题。

class App extends React.Component {
    constructor() {
        super();
        this.state = {
            count: 0,
        }
    }

    fun1() {
        console.log(this);
    }

    fun2 = () => {
        console.log(this);
    }

    fun3() {
        console.log(this);
    }

    render() {
        let { count } = this.state;
        return (
            <div>
	            {/*1.显式绑定this*/}
	            <h2 onClick={this.fun1.bind(this)}>fun1</h2>
	            {/*2.利用箭头函数找到this*/}
	            <h2 onClick={this.fun2}>fun2</h2>
	            {/*3.直接写箭头函数,箭头函数调用回调*/}
	            <h2 onClick={() => console.log(this)}>fun3</h2>
	            <h2 onClick={() => this.fun3()}>fun4</h2>
            </div>
        )
    }
}
root.render(<App />);

3.事件对象和传参

(1)事件对象怎么传

让我们分别看一下这2个绑定事件的按钮:
按钮1:通过bind绑定this,这样的话会默认传一个事件对象event过去,直接就能输出
按钮2:通过箭头函数的话,需要手动传参数过去,默认传的就是event

const root = ReactDOM.createRoot(document.querySelector('#root'));
class App extends React.Component {
    btnClick(e) {
        console.log('e', e);
    }

    render() {
        return (
            <div>
                <button onClick={this.btnClick.bind(this)}>点击奥里给</button>
                <button onClick={(e) => this.btnClick(e)}>箭头函数</button>
            </div>
        )
    }
}
root.render(<App />);

(2)其他参数怎么传?

同样是两种方法,看一下下面两个按钮:
按钮1:通过bind绑定this,传入参数,这里有个大坑,那就是bind后面传的两个参数,传过去会默认放在前两个参数位置,事件对象e就会放在第三个位置,接的时候就是('zzy', 18, 事件对象),这样的话参数就会比较乱,就成了e对应zzy了,这可不行。

按钮2:使用箭头函数传递其他参数,这样的话参数不会乱,比较合适,按顺序传,按顺序接就欧了。但是这里要注意一个问题,就是这个事件对象的参数,如果箭头函数没有传e,那么就不用接收e,形参和实参一一对应就行了;而如果用上面那个按钮1,会自动传事件对象e,这个时候如果传了其他参数,会默认放在参数前几位,事件对象放最后(上面提到了)。

const root = ReactDOM.createRoot(document.querySelector('#root'));
class App extends React.Component {
    btnClick(e, name, age) {
        console.log('e', e);
        console.log('name', name);
        console.log('age', age);
    }

    render() {
        return (
            <div>
                <button onClick={this.btnClick.bind(this, 'zzy', 18)}>bind传参</button>
                <button onClick={(e) => this.btnClick(e, 'zzy', 18)}>箭头函数传参</button>
            </div>
        )
    }
}
root.render(<App />);

二、条件渲染

在vue中,我们使用v-if或v-show进行条件渲染,但是在React中,我们可以直接用原生js语法进行条件渲染,这里提出三种方式:

1.直接if-else

直接在外面定义变量,根据不同情况返回不同的dom结构

constructor() {
    super();
    this.state = {
        isLogin: false,
        friend: {
            name: 'zzy',
        }
    }
}

render() {
    let { isLogin } = this.state;
    let dom = null;
    if (isLogin) {
        dom = <div>登录成功!</div>
    } else {
        dom = <button>重新登录</button>
    }

    return (
        <div>
            {/*1.if-else条件渲染*/}
            <h2>{dom}</h2>
        </div>
    )
}

2.三元表达式

直接通过三元表达式展示不同的dom

constructor() {
    super();
    this.state = {
        isLogin: false,
    }
}

render() {
    let { isLogin} = this.state;
    return (
        <div>
            {/*2.三元运算符*/ }
            <h2>{isLogin ? '登录成功!' : <button>重新登录</button>}</h2>
        </div>
    )
}

3.利用逻辑中断

一般我们从后台获取数据时,就会使用逻辑中断,如果有数据就向后执行,没有数据就不展示。

constructor() {
    super();
    this.state = {
        friend: {
            name: 'zzy',
            description: '我很帅'
        }
    }
}

render() {
    let { friend } = this.state;

    return (
        <div>
            {/*3.逻辑中断,如果后台没有请求到数据就不执行后面的显示*/ }
            <h2>{friend && `我叫${friend.name},${friend.description}`}</h2>
        </div>
    )
}

4.案例练习

点击显示隐藏文本,用if-else实现。

constructor() {
    super();
    this.state = {
        isShow: true,
    }
}

showDom() {
    console.log(this.state.isShow)
    this.setState({
        isShow: !this.state.isShow
    })
}

render() {
    let { isShow } = this.state;
    let message = null;
    if (isShow) {
        message = 'Dj Drop the beat';
    } 

    return (
        <div>
            <button onClick={() => this.showDom()}>点击显示隐藏</button>
            <h2>{message}</h2>
        </div>
    )
}

用三元运算符或逻辑中断实现

return (
	 <div>
	     <button onClick={() => this.showDom()}>点击显示隐藏</button>
	     {/*1.用if-else实现*/}
	     <h2>{message}</h2>
	     {/*2.用三元运算符实现*/}
	     <h2>{isShow ? 'Dj drop the beat' : ''}</h2>
	     {/*3.用逻辑中断*/}
	     <h2>{isShow && 'Dj drop the beat'}</h2>
	 </div>
)

5.模拟v-show的实现

v-show主要是控制display属性,我们只要控制display属性动态变化就可以了。

<h2 style={{ display: isShow ? 'block' : 'none' }}>模拟v-show</h2>

三、列表渲染

列表渲染和vue中的v-for不同,主要用的是数组中的map这个api,同时可以结合filterslice去使用。

使用:我们展示的时候,展示数组就可以了,通过map给数组包一些标签。一般来说会包一个单独的组件。这里要注意map中这个返回标签的话,返回的东西要和return写在一行(比如这个括号),不然默认就return跳出去了(我踩的坑)

constructor() {
    super();
    this.state = {
        student: [
            { id: 1, name: 'zzy', age: 18, sex: '男' },
            { id: 2, name: 'ht', age: 16, sex: '女' },
            { id: 3, name: '张学良', age: 118, sex: '男' },
            { id: 4, name: '杨虎城', age: 18, sex: '女' },
        ]
    }
}

render() {
    let { student } = this.state;
    return (
        <div>
            {student.filter(item => item.age < 20).slice(0,2).map(item => {
                return (
                <div className='active' key={item.id}>
                    <h5>姓名:{item.name}</h5>
                    <h5>年龄:{item.age}</h5>
                    <h5>性别:{item.sex}</h5>
                </div>
                )
            })}
        </div>
    )
}

其中key的唯一标识和vue中原理差不多。

四、jsx的本质

1.babel如何转换

实际上,jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖。
所有的jsx最终都会被转换成React.createElement的函数调用。怎么理解这句话呢?

createElement需要传递三个参数:

  • 参数一:type标签
    当前ReactElement的类型;
    如果是标签元素,那么就使用字符串表示 “div”;
    如果是组件元素,那么就直接使用组件的名称;
  • 参数二:config属性
    所有jsx中的属性都在config中以对象的属性和值的形式存储
  • 参数三:children子元素
    存放在标签中的内容,以children数组的方式进行存储;
    当然,如果是多个元素呢?React内部有对它们进行处理.

所以说其实jsx就是帮助我们调用函数创建虚拟DOM,方便我们编写代码的,比如render中如果我们写下面这段代码:

<div>
    <h2>{count}</h2>
    <ul className='active'>
        <li>我是li1</li>
        <li>我是li2</li>
        <li>我是li3</li>
    </ul>
    <button>按钮</button>
</div>

经过babel转译会变成:

<script>
    /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/

    React.createElement("h2", null, count),
    
     /*#__PURE__*/React.createElement("ul", {className: "active"},
      /*#__PURE__*/React.createElement("li", null, "\u6211\u662Fli1"),
       /*#__PURE__*/React.createElement("li", null, "\u6211\u662Fli2")),

     /*#__PURE__*/React.createElement("button", null, "\u6309\u94AE"));
</script>

这样的话不用babel,我们也可以在页面展示标签,所以jsx就是个语法糖。

2.虚拟DOM的生成

上面的React.createElement 最终创建出来的是一个对象,这个对象组成一个js对象树,就是虚拟DOM
在这里插入图片描述
虚拟DOM帮助我们从命令式编程转到了声明式编程的模式,不会去频繁操作DOM,提升更新效率。

五、购物车案例

在这里插入图片描述
实现上面这个小玩意儿:

<div id="root"></div>
<script type="text/babel">
    const root = ReactDOM.createRoot(document.querySelector('#root'));
    class App extends React.Component {
        constructor() {
            super();
            this.state = {
                books: [
                    {
                        id: 1,
                        name: '《数据结构》',
                        date: '2023-2',
                        price: 56.00,
                        count: 3
                    },
                    {
                        id: 2,
                        name: '《你不知道的js》',
                        date: '2003-2',
                        price: 66.00,
                        count: 1
                    },
                    {
                        id: 3,
                        name: '《进击的巨人》',
                        date: '2013-2',
                        price: 88.00,
                        count: 1
                    },
                ],
            }
        }

        //点击加号或减号,加号传1减号传-1
        changeCount(index, count) {
            //1.对原来的数组进行浅拷贝(内部元素地址还是指向原来)
            const newBooks = [...this.state.books];
            //2.修改浅拷贝后的里面的值
            newBooks[index].count += count;
            //3.此时我们输出books会发现boosk里面对应的值也变了
            console.log(this.state.books[index].count);
            //4.最后调用setState执行render函数更新视图,把newBooks给它(React官方推荐做法)
            this.setState({
                books: newBooks,
            })
        }

        //删除某行数据
        deleteOne(index) {
            console.log(index);
            const newBooks = [...this.state.books];
            newBooks.splice(index,1);
            //操作是一样的,不同的是这里删除不会对books产生影响,因为是浅拷贝
            console.log(this.state.books);//删除某整个对象,books是不变的
            this.setState({
                books: newBooks,
            })
        }

        render() {
            let { books } = this.state;
            let totalPrice = 0;
            books.forEach(book => {
                totalPrice += book.price * book.count;
            });
            return (
                <div>
                    <table>
                        <thead>
                            <tr>
                                <th>序号</th>
                                <th>书籍名称</th>
                                <th>出版日期</th>
                                <th>价格</th>
                                <th>购买数量</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            {books.map((book,index) => {
                                return (
                                    <tr key={book.id}>
                                        <td>{book.id}</td>
                                        <td>{book.name}</td>
                                        <td>{book.date}</td>
                                        <td>{'$' + book.price}</td>
                                        <td>
                                            <button disabled={book.count == 1}
                                            onClick={() => this.changeCount(index,-1)}>-</button>
                                            {book.count}
                                            <button onClick={() => this.changeCount(index,1)}>+</button>
                                        </td>
                                        <td><button onClick={() => this.deleteOne(index)}>移除</button></td>
                                    </tr>
                                )
                            })}
                        </tbody>
                    </table>
                    <h2>总价格:{'$' + totalPrice}</h2>
                </div>
            )
        }
    }
    root.render(<App />);
</script>

总体来说逻辑并不难,主要是涉及到几个地方:
1、总价的计算
2、点击加号和减号改变该行数据
3、点击删除就去掉该行数据
4、没有数据时给用户提示

1.总价的计算

这个搞过很多次了,没什么说的,就是渲染时声明变量,然后遍历求出数量*单价的总和

let totalPrice = 0;
books.forEach(book => {
    totalPrice += book.price * book.count;
});

2.点击加号和减号

这里加减逻辑类似,所以可以封装到一个函数中,参数输了索引之外,还要传入是+1还是-1。

这里的逻辑比较有意思,因为我们不能直接去修改state中的数据,我们要借助调用setState这个方法去修改,从而可以执行render函数更新页面。

React官方推荐的做法是使用一个新的变量浅拷贝原来的数据,然后修改结束之后把新的浅拷贝赋值给state中数据

//点击加号或减号,加号传1减号传-1
changeCount(index, count) {
    //1.对原来的数组进行浅拷贝(内部元素地址还是指向原来)
    const newBooks = [...this.state.books];
    //2.修改浅拷贝后的里面的值
    newBooks[index].count += count;
    //3.此时我们输出books会发现boosk里面对应的值也变了
    console.log(this.state.books[index].count);
    //4.最后调用setState执行render函数更新视图,把newBooks给它(React官方推荐做法)
    this.setState({
        books: newBooks,
    })
}

3.删除某行数据

删除和修改的逻辑是类似的,不过修改是修改对象中某个属性,由于浅拷贝拷贝的是地址,所以修改对象中的属性,那么books和newBooks都会变。但是直接删除其中某个对象,对于浅拷贝来说,books是不会变的。

//删除某行数据
deleteOne(index) {
    console.log(index);
    const newBooks = [...this.state.books];
    newBooks.splice(index,1);
    //操作是一样的,不同的是这里删除不会对books产生影响,因为是浅拷贝
    console.log(this.state.books);//删除某整个对象,books是不变的
    this.setState({
        books: newBooks,
    })
}

4.没有数据时给用户提示

条件渲染,做法有很多,比如之前的if-else。这里我们可以搞两个函数,分别返回有数据和么有数据的DOM,然后在render函数中通过三元表达式决定调用哪个函数。总体的代码是这样的:

<div id="root"></div>
<script type="text/babel">
    const root = ReactDOM.createRoot(document.querySelector('#root'));
    class App extends React.Component {
        constructor() {
            super();
            this.state = {
                books: [......],
            }
        }
        ......

        renderData() {
            let {books} = this.state;
            let totalPrice = 0;
            books.forEach(book => {
                totalPrice += book.price * book.count;
            });
            return(
                <div>
                    <table>
                        <thead>
                            <tr>
                                <th>序号</th>
                                <th>书籍名称</th>
                                <th>出版日期</th>
                                <th>价格</th>
                                <th>购买数量</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            {books.map((book, index) => {
                                return (
                                    <tr key={book.id}>
                                        <td>{book.id}</td>
                                        <td>{book.name}</td>
                                        <td>{book.date}</td>
                                        <td>{'$' + book.price}</td>
                                        <td>
                                            <button disabled={book.count == 1}
                                                onClick={() => this.changeCount(index, -1)}>-</button>
                                            {book.count}
                                            <button onClick={() => this.changeCount(index, 1)}>+</button>
                                        </td>
                                        <td><button onClick={() => this.deleteOne(index)}>移除</button></td>
                                    </tr>
                                )
                            })}
                        </tbody>
                    </table>
                    <h2>总价格:{'$' + totalPrice}</h2>
                </div>
            )
        }

        renderNoData() {
            return <h2>没有数据,去买点东西吧tmd</h2>
        }
        render() {
            let { books } = this.state;
            return books.length ? this.renderData() : this.renderNoData();
        }
    }
    root.render(<App />);
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML#5表单标签

一. 表单标签介绍表单: 在网页中主要负责数据采集功能,使用<form>标签定义表单表单项: 不同类型的input元素, 下拉列表, 文本域<form> 定义表单<input> 定义表单项,通过typr属性控制输入形式<label> 为表单项定义标注<select> 定义下拉列表<o…

【GO】31.grpc 客户端负载均衡源码分析

这篇文章是记录自己查看客户端grpc负载均衡源码的过程&#xff0c;并没有太详细的讲解&#xff0c;参考价值不大&#xff0c;可以直接跳过&#xff0c;主要给自己看的。一.主要接口&#xff1a;Balancer Resolver1.Balancer定义Resolver定义具体位置为1.grpc源码对解析器(resol…

异步通知实验

目录 一、异步通知简介 阻塞、非阻塞、异步通知区别 信号与信号修改测试 测试 二、驱动编写 1、定义fasync_struct 结构体指针变量 2、操作集添加fasync 3、实现imx6uirq_fasync 函数 4、关闭驱动文件操作 ​编辑 5、定时器处理函数 三、编写APP 1、编写信号的处理…

ElasticSearch 学习笔记总结(二)

文章目录一、ES JavaAPI 环境准备二、ES JavaAPI 索引1. 索引 创建2. 索引 查找3. 索引 删除三、ES JavaAPI 文档1. 文档 创建2. 文档 修改3. 文档 查询4. 文档 删除4. 文档 批量新增 和 批量删除5. 高级查询 索引全量查询6. 高级查询四、ES 集群1. ES集群 概念2. window 集群搭…

阿里P8:做测试10年我的一些经验分享,希望你们少走弯路

我是在2015年毕业的&#xff0c;当时是读的普通本科&#xff0c;不上不下的专业水平&#xff0c;毕业的时候&#xff0c;恰好遇到了金融危机。校园招聘里阴差阳错的巧合&#xff0c;让我走上了软件测试工程师的道路。 入职第一天&#xff0c;来了个高大上的讲师&#xff0c;记…

如何使用码匠连接 PostgreSQL

目录 在码匠中集成 PostgreSQL 在码匠中使用 PostgreSQL 关于码匠 PostgreSQL 是一种特性非常齐全的自由软件的对象-关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;它具有许多强大的功能&#xff0c;PostgreSQL 支持大部分的 SQL 标准并且提供了很多其他现…

一些无线通信系统模型的概念

一些无线通信系统模型的概念 扩频通信,指的是系统的带宽WWW远大于其信息传输速率R(bits/s)R(bits/s)R(bits/s), 定义展频带因子BeWRB_e \frac{W}{R}Be​RW​, 易知在扩频通信系统中,BeB_eBe​远大于1. 在频率上产生如此大的冗余度,主要是为了减轻无线通信或卫星通信中经常产生…

关于算法学习和刷题的建议

大家好&#xff0c;我是方圆。最近花时间学了学算法&#xff0c;应该算是我接触Java以来第一次真正的学习它&#xff0c;这篇帖子我会说一些我对算法学习的理解&#xff0c;当然这仅仅是浅浅的入算法的门&#xff0c;如果想深挖或者是有基础的人想提升自己&#xff0c;我觉得这…

【Linux】内核同步机制之等待队列和完成量

文章目录完成量和等待队列1. 等待队列1.1 基本元素1.2 等待队列的创建和初始化1.3 等待队列元素的创建和初始化1.4 添加和移除等待队列元素到等待队列2. 等待事件机制3. 等待队列唤醒4. 总结4.1 等待事件方式4.2 手动休眠方式4.3 借助内核封装函数&#xff0c;进行手动休眠5. 完…

前端开发_快应用开发

目录快应用官网真机调试组件组件嵌套问题tab组件list组件web组件css 样式问题[1]选择器[2]盒模型[3]样式布局-弹性布局[4-1]样式切换 - 类名的动态切换[4-2] 样式切换 - 行内样式动态切换[5]background[6]overflow[7]border-radius[8]盒子阴影[9] 单位系统接口[1] 检查某app是否…

机房运维6大隐患,你中了几个?

随着医院的看诊预约、缴费、打印报告等众多业务转至线上进行&#xff0c;对医院的网络及数据处理能力提出越来越高的要求&#xff0c;那么&#xff0c;机房的稳定、安全运行是医院网络信息系统的关键因素。 机房运维6大隐患 01.电源电力系统不稳定&#xff0c;网络设备运转遭到…

华为面试题就这?00后卷王直接拿下30k华为offer......

先说一下我的情况&#xff0c;某211本计算机&#xff0c;之前在深圳那边做了大约半年多少儿编程老师&#xff0c;之后内部平调回长沙这边&#xff0c;回来之后发现有点难&#xff0c;这边可能是业绩难做&#xff0c;虚假承诺很厉害&#xff0c;要给那些家长虚假承诺去骗人家&am…

红日(vulnstack)1 内网渗透ATTCK实战

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;sx22 攻击机系统&#xff1a;kali linux 2022.03 网络配置&#xff1a; win7配置&#xff1a; kali配置&#xff1a; kali 192.168.1.108 192.168.111.129 桥接一块&#xff0c;自定义网卡4 win7 1…

一文读懂云渲染“串流”全链路时延及优化策略

​这是一个让云游戏完美起步的时代。 云游戏作为产业内近年来炙手可热的话题&#xff0c;具有“云端运行、超高清、零延时、即点即玩”等众多特性。 随着 5G 时代的到来&#xff0c;以及中心云能力下沉至边缘云&#xff0c;高带宽、低延迟、高性能这些特性与云游戏紧密结合&a…

FastDDS-2.库概览

2. 库概览 Fast DDS&#xff08;前身为Fast RTPS&#xff09;是DDS规范的高效高性能实现&#xff0c;DDS规范是一种用于分布式应用软件的以数据为中心的通信中间件&#xff08;DCPS&#xff09;。本节回顾Fast DDS的体系结构、操作和关键特性。 2.1 架构 Fast DDS的架构如下图…

07_MySQL的单行函数

1. 函数的理解1.1 什么是函数函数在计算机语言的使用中贯穿始终&#xff0c;函数的作用是什么呢&#xff1f;它可以把我们经常使用的代码封装起来&#xff0c;需要的时候直接调用即可。这样既提高了代码效率 &#xff0c;又提高了可维护性 。在 SQL 中我们也可以使用函数对检索…

python之wheel 包命名规则、abi 兼容和安装

一、windows安装python包&#xff0c;遇见的问题 1、python3以后的版本&#xff0c;安装python包&#xff0c;可以直接使用pip安装&#xff0c;但是安装时偶尔报错 2、安装python源码包&#xff0c;如何确定自己该安装哪个版本&#xff0c;一看就晕倒~~~&#xff08;没人扶&…

PMP新考纲考试难不难,通过率怎样?

PMP考试难不难&#xff0c;还是因人而异的&#xff0c;对小白而言&#xff0c;肯定是难的&#xff0c;对项目管理老人而言&#xff0c;难度肯定是没那么高。 据考过的朋友讲&#xff0c;新考纲是有点难度的&#xff0c;尤其是最开始6月25日的考试&#xff0c;2023年就简单些了…

职场性别报告,男女薪酬仍有差距,男性平均薪酬比女性高29.7%

性别是否影响职业&#xff1f;女性求职比男性更加困难&#xff1f;男性薪酬比女性更有优势&#xff1f;人们一说到警察、建筑师通常会想到高大魁梧的男性形象&#xff0c;一说到幼师、护士往往想到的都是温柔的女性形象&#xff0c;职业好似与性别挂钩&#xff1b;女性求职通常…

OnlyOffice验证(二)在Centos7上部署OnlyOffice编译结果

在Centos7上部署OnlyOffice编译结果 此处将尝试将OnlyOffice验证&#xff08;一&#xff09;DocumentServer编译验证的结果部署到Centos7上。并且使用其它服务器现有的RabbitMq和Mysql。 安装Nginx 先安装Nginx需要的依赖环境&#xff1a; yum install openssl* -y yum insta…