删除工程依赖
rm -f /node_modules
1.适配
rem与px互换
1rem等于html根元素设定的font-size的px值,假如我们在css里面设定下面的css。
html{font-size:14px}
那么后面的CSS里面的rem值则是以这个14来换算,例如设定一个div宽度为3rem,高度为2.5rem.则它换算成px为width:42px.height:35px,同理,假如一个设计稿为宽度42px,高度为35px,则换成成rem,则是42/14=3rem,35/14=2.5rem。
如果css里面没有设定html的font-size,则默认浏览器以1rem=16px来换算。
现在使用
2.定位和样式问题
1.子元素相对父元素居中,相对定位
<style>
.album-img {
position: relative;
display: flex;
justify - content: center;
}
.diary-control {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify - content: center;
}
</style>
2.设置字体垂直居中
line-height: 100%;
3.圆角设置
设置宽度一般,圆形
border-radious: 100%;
3.div 嵌套 img 标签,底部有白底
1.是图片的底就得重新做图
2.是样式的底的话就把样式的背景色去掉
3.子标签没有颜色,其他标签有颜色也会覆盖.
4.div子标签水平排布
<style>
.userHeader {
display:flex;
img {
margin - left:1.63 rem;
background - color:lightgray;
width:3.63 rem;
height:3.63 rem;
border - radius:1.82 rem;
}
.label {
margin - top:1.06 rem;
margin - left:1.63 rem;
color:#FFFFFF;
flex:1;
text - align:center;
justify - content:center;
}
}</style>
5.React添加百度统计代码
- 页面埋点
- 点击事件埋点
语法
_hmt.push(['_trackEvent', category, action, opt_label, opt_value]);
举例
_hmt.push(['_trackEvent', 'music', 'play', 'Hey Jude']);
category 必选 String 要监控的目标的类型名称 不填、填"-"的事件会被抛弃
action 必选 String 用户跟网页进行交互的动作名称 不填、填"-"的事件会被抛弃
opt_label 可选 String 事件的一些额外信息 不填、填"-"代表此项为空
opt_value 可选 Number 跟事件相关的数值
实现代码
componentDidMount() {
this.baiduStatistics();
this.handlePageCounts();
}
/**
* 百度统计初始化
*/
export function baiduStatistics() {
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?18fd37d414145c525285e6cf0f11dada";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
}
//页面访问量
handlePageCounts() {
setTimeout(function(){
window._hmt.push(['_trackEvent', "pageName", "页面访问", "访问量",1]);
},500)
}
/**
* 发送事件分析
* @param pageName 页面名称
* @param action 动作
* @param flag 标签/id
*/
export function baiduStatisticsBehaviour(pageName, action, flag) {
if(typeof window._hmt == 'undefined') return;
window._hmt.push(['_trackEvent', pageName, action, flag,1]);
}
//使用:
baiduStatisticsBehaviour('XXX落地页','行为描述','标记名称')
//注意,不同的域名,他的token值是不一样的,需要区分,页面访问展示很快,点击事件需要两个小时以后才可以展示在百度后台数据上
6.React加载带<br/>
的字符串
let data = "1.在语音日记中可以记录生活、故事、诗词、绕口令、笑话、外语、朗诵等。<br/><br/> 2.每人每天最多记录两条日记,包括已删除的日记。<br/><br/>3.日记时长限制在10秒至3分钟。"
<div className="activityDetail">
<div className="detail" dangerouslySetInnerHTML={{ __html: data}}>
</div>
</div>
7.去掉微信签名-方便调试
componentDidMount() {
let sign = getQueryString('sign') || Cookies.get('sign')
//if (sign) {
this.requestList()
this.initPlay()
advert({
operate: 'diarymission',
label: 'open_diary_page',
}).then((res) => {})
//}
}
8.图片添加自旋转动画
<style>
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin;
pointer-events: none;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>
9.react使用引入svg的icon;svg图形制作
https://blog.csdn.net/weixin_34319817/article/details/86017954
10.数据驱动UI,根据返回数据创建多个标签
//用户头像For
import UserHeader from '../../components/groupbuy/UserHeader'
//定义数据源
persons: [
"周家大小姐",
"陈家大小姐",
"王家大小姐",
]
<div className="buyNumbers">
<div className="nums">
{
persons.map((person) => {
console.log("person"+person);
return (
// 对map 循环出来的每个属性插入标签元素
<UserHeader name={person} />
)
})
}
</div>
<div className="desc">{"等N人已购买"}</div>
</div>
11.React 单页应用中,使用less写样式,公共样式文件重复载入(样式名冲突导致界面引用错乱)
解决办法
react中css设置作用域
Less 中的作用域与编程语言中的作用域概念非常相似。首先会在局部查找变量和混合,如果没找到,编译器就会在父作用域中查找,依次类推
//定义scope
@var: red;
#page {
@var: white;
#header {
color: @var; // white
}
}
#mynamespace {
.home {}
.user {}
}
这样我们就定义了一个名为 mynamespace 的命名空间,如果我们要复用 user 这个选择器的时候,
我们只需要在需要混入这个选择器的地方这样使用就可以了。#mynamespace > .user。
#circle(@size: 25px){
background-color: #4CAF50;
border-radius: 100%;
width: @size;
height: @size;
}
#small-circle{
#circle
}
#big-circle{
#circle(100px)
}
第二种
在标签名后➕-container
例如
<style>
.special-container{
padding: 0 1rem;
.banner{
height: 100%;
width: 100%;
margin-top: 1rem;
box-shadow: 0 .125rem .625rem 0 rgba(0,0,0,0.10);
border-radius: .375rem;
img{
width: 100%;
height: 8.4375rem;
border-radius: .375rem;
}
}
}
</style>
12.测试开发之switch-case语法
1.props定义属性:pageState
constructor(props) {
super(props);
this.state = {
pageState: "0",
}
}
2.render 修改
<div>
{( ()=>{
switch(this.state.pageState){
case "0":return <img src={gift1}/>; break;
case "1":return <img src={gift2}/>; break;
case "2":return <img src={gift3}/>; break;
default:return null;
}
}
)()}
</div>
3.使用:修改pageState数值,点击保存即可
13.获取Url拼接的参数
// 获得URL参数
const query_params = new
//问号之前的内容
URLSearchParams(this.props.location.search);
console.log("参数"+query_params);
let state = query_params .get('pageState');
console.log("pageState:"+state);
this.setState({
pageState: state,
});
14.URL跳转
封装跳转方法
export function urlJump(params) {
window.location.href = window.location.protocol + '//' + window.location.host + params
}
使用
invite = (id) => {
urlJump("/fission/invite/" + id)
}
15.方法名传参数(bind)
类的方法默认是不会绑定 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined
//e.preventDefault()
取消事件的默认动作
例如,如果 type 属性是 "submit",在事件传播的任意阶段可以调用任意的事件句柄,通过调用该方法,可以阻止提交表单。
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件对象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
<div>
<p>hello</p>
{/* 通过 bind() 方法传递参数。 */}
<a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
</div>
);
}
}
16.KeyFrame动画案例-(标签抖动效果)
代码
<div className="getFreeBtn">
<div class="btn" onClick={this.handleDownload.bind(this,'1','getFree','getFree_downloadBtn')}></div>
</div>
less样式
.getFreeBtn {
background:url('../../images/diary/diary_unlock_getFreeBtnBg.png') no-repeat;background-size:100%;
width: 21.44rem;
height: 8.1rem;
line-height:0;
display: flex;
position: relative;
.btn{
position: absolute;
bottom: -1rem;
left: 0;
right: 0;
width: 21.44rem; height: 2.88rem; display: block; background: url('../../images/diary/diary_unlock_getFreeBtn.png') no-repeat;background-size:100% ;
animation: bounce 1.2s cubic-bezier(0.67, 0.04, 0.32, 0.96) infinite forwards;
}
}
@keyframes bounce {
0% {
transform: scale(1);
}
30% {
transform: scale(0.8);
}
40% {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
65% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
效果图
17.React设置文字溢出,多余显示省略号
单行文本
<style>
.text {
display: inline-block;
white-space: nowrap; //强制不换行
overflow: hidden;//超出隐藏
text-overflow:ellipsis;// [ɪˈlɪpsɪs] 显示“……”
}
</style>
多行文本
<div className="orderDesc">
<p style={{"WebkitBoxOrient": "vertical"}}>{"多行文本溢出,多行文本溢出,多行文本溢出,多行文本溢出"}</p>
</div>
//CSS
.orderDesc {
margin-left: 1.3rem;
margin-right: 0.56rem;
margin-top: 0.38rem;
margin-bottom: 0;
width: 11.75rem;
height: 3.75rem;
// background: yellow;
p{
font-size: 0.88rem;
line-height: 1.25rem;
text-align: left;
color: #515151;
display: -webkit-box;
-webkit-box-orient: vertical;//react项目中发现并不能实现 style={{"WebkitBoxOrient": "vertical"}}
-webkit-line-clamp: 3;
overflow: hidden;
}
}
文本溢出第三种处理:flex
.v-item {
display: flex;
justify-content: space-between;
p {
margin-left: 0.5rem;
width: 70%;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
.time{
display: flex;
justify-content: flex-end;
margin-right: 0.5rem;
width: 20%;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
// background: yellow;
}
}
18.监听滚动事件改变标签的样式
componentDidMount() {
//1.添加滑动监听
window.addEventListener('scroll', this.handleScroll);
}
/**
* 滚动事务
* @private
*/
handleScroll=(event)=>{
//滚动条高度
let ctx=this;
//可视区域高度
let clientHeight = document.documentElement.clientHeight;
//滚动条滚动高度
let scrollTop = document.documentElement.scrollTop;
//滚动内容高度
let scrollHeight =document.documentElement.scrollHeight;
// 距离页面底部的高度
const height = scrollHeight - scrollTop - clientHeight;
console.log("clientHeight:"+clientHeight+"scrollTop:"+scrollTop+"scrollHeight"+scrollHeight+"height:"+height);
if (scrollTop<100) {
this.setState({
isScroll: false
})
}else {
this.setState({
isScroll: true
})
}
}
使用
{/* 定义props isScroll 根据偏移量 设置不同的ClassName */}
<div className= {isScroll ? "fixed-joinGroup" : "group-joinGroup"} onClick={this.handleJoinGroupNow}>
<div className="title">
{"一键参团"}
</div>
</div>
{/* CSS样式设置 */}
.group-joinGroup {
width: 100%; display: flex; justify-content: center;
.title {
padding-top: 0.69rem;
padding-bottom: 0.69rem;
width: 20rem;
background-color: #FF1634;
border-radius:1.38rem; line-height: 100%;
font-size: 1rem;
color: #ffffff;
margin-bottom: 10px;
}
}
.fixed-joinGroup {
.title {
padding-top: 0.69rem;
padding-bottom: 0.69rem;
position: fixed;
left: 0px;
right: 0px;
margin-left:auto;
margin-right:auto;
bottom: 1rem;
width: 20rem;
background-color: #FF1634;
border-radius:1.38rem; line-height: 100%;
font-size: 1rem;
color: #ffffff;
}
}
效果图:
19.Flex 布局相关
display: flex;//想使用Flex布局,必须使用这个属性
justify-content: flex-end;
1.设置单个子元素靠右
父元素设置了 flex 布局
display: flex;
align-items: center;
如何让某个子元素靠右呢
方法一
flex: 1;
text-align: right;
方法二
margin-left: auto;
2.设置绝对居中
<div id="newInstall-body">
<div className="title-views"></div>
</div>
//CSS
#newInstall-body{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.title-views {
display: flex;
margin-top: 1.13rem;
margin-left: 0.63rem;
margin-right: 0.63rem;
margin-bottom: 0;
//宽度不设置,默认继承父元素
height: 4.25rem;
background-color: red;
}
}
3.设置图片100%显示
#newGuide-body{
background: url(../../images/promotion/promotion_newInstall_bg.png) no-repeat;
background-size:100% 100%;
width: 100%;
height: 100%;
}
4.设置标签内内容居右显示
.action-btn {
display: flex;
justify-content: flex-end;
margin-right: 0.63rem;
.un-shipped {
width:5.63rem;
height: 1.63rem;
}
.shipped {
width:5.63rem;
background:rgba(255,220,53,1);
}
}
20.react中获取input输入框内容的两种方法
1.通过event对象信息的方式
<input onChange={(e)=>this.inputChange(e)}/>
<button onClick={()=>this.getInputValue} >获取input的值</button>
inputChange(e){
alert(e.target.value)
this.setState({
username:e.target.value
})
}
getInputValue(){
alert(this.state.username)
}
2.使用ref的方式
<div className="receiver-name">
<input ref="name" onChange={()=>this.inputChange()} className="form-control" id="receiverName" name="receiverName" placeholder="请输入收货姓名" />
</div>
<div className="receiver-phone">
<input ref="phone" onChange={()=>this.inputChange()} className="form-control" id="receiverPhone" name="receiverPhone" placeholder="请输入收货电话" />
</div>
<button onClick={()=>this.getInputValue()} >获取input的值</button>
//数据赋值
inputChange(){
//获取dom节点元素
//1.添加ref属性
//2.使用this.refs.receiverName获取dom节点
let name = this.refs.name.value;
let phone = this.refs.phone.value;
let address = this.refs.address.value;
console.log(name,phone,address);
this.setState({
receiverName:name,
receiverPhone:phone,
receiverAddress: address,
})
}
handleSubmit(){
let message = "姓名:"+this.state.receiverName+"\n"+"手机号:"+this.state.receiverPhone+"\n"+"地址:"+this.state.receiverAddress
console.log("message:"+message);
this.onOk();
}
21.复制操作
1.表单简单复制操作-(只支持浏览器)
<p>点击复制后在右边textarea CTRL+V看一下</p>
<input type="text" id="inputText" value="测试文本"/>
<input type="button" id="btn" value="复制"/>
<textarea rows="4"></textarea>
<script type="text/javascript">
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
var inputText = document.getElementById('inputText');
var currentFocus = document.activeElement;
inputText.focus();
inputText.setSelectionRange(0, inputText.value.length);
document.execCommand('copy', true);
currentFocus.focus();
});
</script>
2.通用复制操作-copy-to-clipboard
安装插件
npm install --save copy-to-clipboard
使用帮助
#引入插件
import copy from 'copy-to-clipboard';
if(copy("http://baidu.com")){
console.log("复制成功");
}else{
console.log("复制失败")
}
3.react-copy-to-clipboard
安装插件
npm install --save react-copy-to-clipboard
使用帮助
#引入插件
#this.onCopy 复制之后执行的方法
import CopyToClipboard from 'react-copy-to-clipboard';
<CopyToClipboard text="http://baidu.com"
onCopy={this.onCopy}>
<span>Copy to clipboard with span</span>
</CopyToClipboard>
22.React 多个Audio 实例控制只播放当前的,暂停其他Audio实例
关键代码
// 暂停函数
pauseAllAudio = () => {
var audios = document.getElementsByTagName("audio");
// 暂停函数
function pauseAll() {
var self = this;
[].forEach.call(audios, function (i) {
// 将audios中其他的audio全部暂停
i !== self && i.pause();
})
}
// 给play事件绑定暂停函数
[].forEach.call(audios, function (i) {
i.addEventListener("play", pauseAll.bind(i));
})
}
//Audio实例播放方法
fourthAudioPlay = () => {
baiduStatisticsBehaviour('日记分享落地页', '点击', 'h5_riji_zj4');
//暂停其他实例
this.pauseAllAudio();
let fourthAudio = this.refs.fourth
if (fourthAudio.paused) {
fourthAudio.play();
} else {
fourthAudio.pause();
}
}
使用
<audio ref="first" src={data && data.diary_mission ? data.diary_mission.mp3 : '' } style={{display: 'none'}}>
Your browser does not support the audio element.
</audio>
<audio ref="second" src={data && data.diary_mission ? data.diary_mission.mp3 : '' } style={{display: 'none'}}>
Your browser does not support the audio element.
</audio>
<audio ref="third" src={data && data.diary_mission ? data.diary_mission.mp3 : '' } style={{display: 'none'}}>
Your browser does not support the audio element.
</audio>
<img onClick={this.fourthAudioPlay}
src={ fourthPaused ? smallPlayImg: smallPauseImg}
alt=""/>
23.React-JS (拼团添加人数逻辑)
拼团添加人数逻辑:Server返回数据不满足最大人数8时,剩余人数由自己创建假数据
关键代码
var members = res.groupbuyCate.member;
let pageState = res.groupbuyCate.pageState;
console.log("members:"+members);
if (typeof members != 'undefined'){
members.map((member) => {
items.push(member);
});
}
console.log("items:"+items.length);
if (items.length < 8){
let count = 8 - items.length;
console.log("count:"+count);
for(var i = 0; i < count; i++){
items.push({ id: i,path:addBg});
}
}
console.log(items);
//遍历输出对象
items.map((item)=>{
console.log("Final:"+item.id);
})
this.setState({
persons: items,
pageState: pageState,
})
24.解决新版微信中H5页面底部白条问题
问题描述:
微信将后退的按钮移至了底部横栏,遮挡住了原先底部的操作按钮。
分享微信好友进入有底部导航栏,点击链接进入没有导航栏
分析:
点击链接进入 -> 不需要授权
点击微信分享App图标进入 -> 需要授权
如果进入H5首页每次都要微信授权来获取用户信息,那这个白条将每次都会出现,因为oauth授权一定会有跳转。第一次授权跳转是无法避免的,那么只要避免用户进行二次授权,也就避免了白条的再次出现。
结果:只要授权就会有底部导航:所以,解决问题的关键点在于如何避免微信二次授权。
解决思路
- 第一次微信授权,存储必要参数到Cookie
- 第二次先从Cookie中取参数,取到了就不跳授权
- 第二次取不到就跳微信授权
代码:
componentWillMount = () => {
let w = document.documentElement.clientWidth;
console.log("width"+w);
this.setState({
width:w
})
initParameter();
let sign = getParameter('sign')
if (!sign && this.state.client == 1) {
let url = "微信授权Url"
window.location.href = url;
} else {
this.setState({
sign: true
})
}
let openid = getQueryString('openid');
if(openid.length >= 20) {
Cookies.set('openid', openid);
}
}
//初始化基础参数
export function initParameter() {
let sign = getQueryString('sign');
let sso_id = getQueryString('sso_id');
let openId = getQueryString('openId');
sign && Cookies.set('sign', sign);
sso_id && Cookies.set('sso_id', sso_id);
openId && Cookies.set('openid', openId);
}
//获取基础参数(从Cookie)
export function getParameter(param) {
let val = Cookies.get(param) || getQueryString(param)
if(!val && param !== 'sign') {
alert(param + 'empty')
return
}
return val
}
//获取Url拼接参数
export function getQueryString(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg);
// let r = window.location.search.substr(1).replace('?', '&').match(reg);
if (r !== null) return decodeURIComponent(r[2]);
return 0;
}
亲测可实现隐藏效果
效果图:
25.页面大图处理
#exchange-voucher-body {
background: url(../../images/voucher/activity_voucher_bg.png) no-repeat #1EB8FF;
background-size:100%;
width: 100%;
height: 100%;
}
显示效果
26.React 刷新当前页(倒计时结束)
countDowntimeEndCallBack(){
// Toast.show("时间到");
let reload = Cookies.get(global.cookiePrefix + "reload"+getParameter('groupbuy_id'));
if (reload != 1){
window.location.reload();
Cookies.set(global.cookiePrefix + "reload"+getParameter('groupbuy_id'),1);
}
}
27. js判断对象是否为空的几种方法
1.将json对象转化为json字符串,再判断该字符串是否为"{}"
var data = {};
var b = (JSON.stringify(data) == "{}");
alert(b);//true
2.jquery的isEmptyObject方法
此方法是jquery将2方法(for in)进行封装,使用时需要依赖jquery
var data = {};
var b = $.isEmptyObject(data);
alert(b);//true
3.使用ES6的Object.keys()方法
//返回值也是对象中属性名组成的数组
var data = {};
var arr = Object.keys(data);
alert(arr.length == 0);//true
28.React JS setTimeout 不能使用this.属性名,否则报错-参数未定义
let isOpenGroup = this.state.pageState == "1";
setTimeout(function () {
//this.state.pageState 在block 内会报错
if(isOpenGroup){
console.log("未开团");
}else {
console.log("已开团");
}
},500);
29.document.documentElement.scrollTop在手机端无效的解决方法
问题:广告不会随着页面滚动而浮动
分析:标准浏览器是只认识documentElement.scrollTop
的,但chrome虽然我感觉比firefox还标准,但却不认识这个,在有文档声明时,chrome也只认识document.body.scrollTop
.
因为document.body.scrollTop与document.documentElement.scrollTop两者有个特点,就是同时只会有一个值生效。比如document.body.scrollTop能取到值的时候,document.documentElement.scrollTop就会始终为0;反之亦然。
所以,如果要得到网页的真正的scrollTop值,可以这样:
//滚动条滚动高度
let scrollTop = document.documentElement.scrollTop+document.body.scrollTop;
30.React 改变this的指向
- 通过bind来指明当前方法中的this指向当前组件
export default class Test extends React.Component {
constructor () {
super()
this.value = 1
}
run () {
console.log(this.value)
}
render () {
return <div>
<button onClick={this.run.bind(this)}>点我</button>
</div>
}
}
- 在构造函数
constructor
中改变this指向
export default class Test extends React.Component {
constructor () {
super()
this.value = 1
this.run = this.run.bind(this)
}
run () {
console.log(this.value)
}
render () {
return <div>
<button onClick={this.run}>点我</button>
</div>
}
}
- 使用箭头函数改变this指向
export default class Test extends React.Component {
constructor () {
super()
this.value = 1
}
run = (e) => {
console.log(e)
console.log(this.value)
}
render () {
return <div>
<button onClick={this.run}>点我</button>
</div>
}
}
31.React兄弟组件间传值,动态更新标题
方法一
引进Redux,通过StoreProvider获取全局状态
方法②
用state和props配合传值,通过输入框组件的onchange函数监听输入框的值的变化,然后去更新当前页面的state,将state的值传入到另一个组件中,实现兄弟间传值
export default class Page extends Component {
static displayName = 'Page';
constructor(props) {
super(props);
console.log(props);
this.state = {
name:'111',
};
}
onChange = (value) => {
this.setState({name:value});
};
render() {
const name1 = this.state.name
return (
<div className="page"><br/><br/>
<TestimonialCard name={name1} />
<Input
hasClear
defaultValue="clear by click"
size="small"
aria-label="input with config of hasClear" value={this.state.name} onChange={this.onChange} />
</div>
);
}
}
组件TestimonialCard关于传值的代码
constructor(props) {
super(props);
this.state = {name:props.name};
}
componentWillReceiveProps(props){
this.state = {name:props.name};
}
32.React Diff算法
计算出Virtual DOM中真正变化的部分,并只针对该部分进行原生DOM操作,而非重新渲染整个页面,需要明确的是,进行比较的是两个组件
- 节点不同,React 直接抛弃旧的节点生成新的节点
- 判断是否自定义节点(不会删除节点,在原来的节点上进行操作)-> 是->state不同 重新渲染, 更新Dom ,state未变化, 不更新Dom
- 不是自定义节点-> 比较属性 class/id