desk

desk 查看完整档案

东莞编辑  |  填写毕业院校  |  填写所在公司/组织 blog.irsk.cn 编辑
编辑

Freshman

个人动态

desk 赞了回答 · 8月13日

解决ob_flush在PHP7中实时打印foreach里的echo不能用?

ob_flush 的确是输出缓冲区没错

但 NGINX 和 php-fpm 之间还有一层缓冲区, 不是 php 的 output buffer 函数可以控制的.

有几个地方需要调整, 你可以自己试试(取其一即可):

  1. PHP 输出一个 header('X-Accel-Buffering: no'); 的 HTTP Response Header, 仅影响当前请求
  2. 全局层面关闭 nginx 的 fastcgi 的缓冲, 配置为: fastcgi_buffering, 文档: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_buffering

或者干脆考虑换方案, 例如 websocket

关注 2 回答 1

desk 提出了问题 · 8月13日

解决ob_flush在PHP7中实时打印foreach里的echo不能用?

参考教程
https://segmentfault.com/a/1190000005972877

我的环境环境 PHP 7.2+ nginx 1.18,gizp已经关闭
但是还是在执行完后才一起输出。
有朋友知道问题点在哪里吗?
谢谢

关注 2 回答 1

desk 赞了回答 · 6月10日

解决Magento `getFinalPrice()` 方法无法获得正确价格

解决:先查询并设置用户组 然后就可得出相应客户组的正确价格

...
# @ Customer GroupId
$Int_Customer_GroupId = $customer -> getGroupId();
# @ Set Group
$product -> setCustomerGroupId( $Int_Customer_GroupId );
# @ Final Price
$finalPrice = $product -> getFinalPrice();
...

关注 1 回答 1

desk 关注了专栏 · 2018-12-26

树莓派小无相系列

树莓派的一百种折腾方式

关注 12

desk 收藏了文章 · 2018-12-20

从入门到上线一个天气小程序

前言

学习了一段时间小程序,大致过了两遍开发文档,抽空做个自己的天气预报小程序,全当是练手,在这记录下。小程序开发的安装、注册和接入等流程就不罗列了,在小程序接入指南已经写得很清楚了,以下只对开发过程常用到得一些概念进行简单梳理,类比 Vue 加强记忆,最后选取个人项目天气小程序中要注意的几点来说明。

minWeather

欢迎扫码体验

minWeather

源码请戳这里,欢迎start~

初始化项目目录结构

安装好开发者工具,填好申请到的AppID,选好项目目录,初始化一个普通小程序目录结构,得到:

--|-- pages
    |-- index
      |-- index.js // 首页js文件
      |-- index.json // 首页json文件
      |-- index.wxml // 首页wxml文件
      |-- index.wxss // 首页wxss文件
    |-- logs
      |-- logs.js // 日志页js文件
      |-- logs.json // 日志页json文件
      |-- logs.wxml // 日志页wxml文件
      |-- logs.wxss // 日志页wxss文件
  |-- utils
    |-- util.js // 小程序公用方法
  |-- app.js // 小程序逻辑
  |-- app.json // 小程序公共配置
  |-- app.wxss // 小程序公共样式表
  |-- project.config.json // 小程序项目配置

可以看到,项目文件主要分为.json.wxml.wxss.js类型,每一个页面由四个文件组成,为了方便开发者减少配置,描述页面的四个文件必须具有相同的路径与文件名。

JSON配置

小程序配置 app.json

app.json配置是当前小程序的全局配置,包括小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。

工具配置 project.config.json

工具配置在小程序的根目录,对工具做的任何配置都会写入这个文件,使得只要载入同一个项目代码包,开发则工具会自动恢复当时你开发项目时的个性设置。

页面配置 page.json

页面配置 是小程序页面相关的配置,让开发者可以独立定义每个页面的一些属性,比如顶部颜色,是否下拉等。

WXML 模板

WXML 充当类似 HTML 的角色,有标签,有属性,但是还是有些区别:

  1. 标签名不一样。
    HTML 常用标签 <div><p><span>等,而小程序中标签更像是封装好的组件,比如<scroll-view>, <swiper>, <map>,提供相应的基础能力给开发者使用。
  2. 提供 wx:if,{{}}等模板语法。
    小程序将渲染和逻辑分离,类似于ReactVueMVVM开发模式,而不是让 JS 操作 DOM

下面针对小程序的数据绑定、列表渲染、条件渲染、模板、事件和应用跟 Vue 类比加深记忆。

数据绑定

WXML 中的动态数据均来自对应 Page(或 Component) 的 data,而在 Vue中来自当前组件。

小程序和Vue的数据绑定都使用 Mustache 语法,双括号将变量包起来。区别是 Vue 中使用Mustache 语法不能作用在 HTML 特性上

<div v-bind:id="'list-' + id">{{msg}}</div>

而小程序作用在标签属性上

<view id="item-{{id}}">{{msg}}</view>

列表渲染

Vue 中使用 v-for 指令根据一组数组的选项列表,也可以通过一个对象的属性迭代进行渲染,使用 (item, index) in items(item, index) of items 形式特殊语法。

<ul>
  <li v-for="(item, index) in items">
    {{ index }} - {{ item.message }}
  </li>
</ul>

渲染包含多个元素,利用 <template>元素

<ul>
  <template v-for="(item, index) in items">
    <li>{{ index }} - {{ item.message }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

而在小程序中使用 wx:for 控制属性绑定一个数组(其实对象也可以),默认数组的当前项的下标变量为 index ,当前项变量为 item

<view wx:for="{{items}}"> {{index}} - {{item.message}} </view>

也可以用 wx:for-item 指定数组当前元素的变量名,用 wx:for-index 指定数组当前下标的变量名。

<view wx:for="{{items}}" wx:for-index="idx" wx:for-item="itemName">
  {{idx}}: {{itemName.message}}
</view>

渲染一个包含多节点的结构块,利用 <block> 标签

<block wx:for="{{items}}">
  <view> {{index}} - {{item.message}} </view>
  <view class="divider" role="presentation"></view>
</block>

条件渲染

Vue 中使用v-ifv-else-ifv-else指令条件渲染,多个元素使用<template>包裹,而小程序中使用wx:ifwx:elseifwx:else来条件渲染,多个组件标签使用<block>包裹。

模板

Vue 中定义模板一种方式是在 <script> 元素中,带上 text/x-template 的类型,然后通过一个id将模板引用过去。

定义模板:

<script type="text/x-template" id="hello-world-template">
  <p>Hello hello hello</p>
  <p>{{msg}}</p>
</script>

使用模板:

Vue.component('hello-world', {
  template: '#hello-world-template',
  data () {
    return {
      msg: 'this is a template'
    }
  }
})

而在小程序中,在 <template> 中使用 name 属性作为模板名称,使用 is 属性声明需要使用的模板,然后将模板所需的 data 传入。

定义模板:

<template name="hello-world-template">
  <view>Hello hello hello</view>
  <view>{{msg}}</view>
</template>

使用模板:

<template is="hello-world-template" data="{{...item}}"></template>
Page({
  data: {
    item: {
      msg: 'this is a template'
    }
  }
})

事件

Vue 中,用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码,对于阻止事件冒泡、事件捕获分别提供事件修饰符.stop.capture的形式

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

而在小程序中,绑定事件以 keyvalue 的形式,keybindcatch 开头,然后跟上事件的类型,如 bindtapcatchtouchstart,也可紧跟一个冒号形式,如 bind:tapcatch:touchstartbind 事件绑定不会阻止冒泡事件向上冒泡,catch 事件绑定可以阻止冒泡事件向上冒泡。

<!-- 单击事件冒泡继续传播 -->
<view bindtap="doThis">bindtap</view>
<!-- 阻止单击事件冒泡继续传播 -->
<view catchtap="doThis">bindtap</view>

采用 capture-bindcapture-catch 分别捕获事件和中断捕获并取消冒泡。

<!-- 捕获单击事件继续传播 -->
<view capture-bind:tap="doThis">bindtap</view>
<!-- 捕获单击事件阻止继续传播,并且阻止冒泡 -->
<view capture-catch="doThis">bindtap</view>

引用

Vue 中引用用于组件的服用引入

import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

在小程序中,WXML 提供两种引用方式 importinclude

在 item.wxml 中定义了一个叫item的template:

<!-- item.wxml -->
<template name="item">
  <text>{{text}}</text>
</template>

在 index.wxml 中引用了 item.wxml,就可以使用item模板:

<import data-original="item.wxml" /> <template is="item" data="{{text: 'forbar'}}" />

include 可以将目标文件除了 <template><wxs> 外整个代码引入:

<!-- index.wxml -->
<include data-original="header.wxml" /> <view> body </view> <include data-original="footer.wxml" />
<!-- header.wxml -->
<view> header </view>
<!-- footer.wxml -->
<view> footer </view>

WXSS 样式

WXSS(WeiXin Style Sheets) 具有 CSS 大部分的特性,也做了一些扩充和修改。

尺寸单位rpx

支持新的尺寸单位 rpx,根据屏幕宽度自适应,规定屏幕宽为750rpx,免去开发换算的烦恼(采用浮点计算,和预期结果会有点偏差)。

设备rpx换算px(屏宽/750)px换算rpx(750/屏宽)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

iPhone6上,换算相对最简单,1rpx = 0.5px = 1物理像素,建议设计师以 iPhone6 为设计稿。

样式导入

使用 @import 语句导入外联样式表,注意路径为相对路径。

全局样式与局部样式

app.wxss中的样式为全局样式,在 Page (或 Component) 的 wxss文件中定义的样式为局部样式,自作用在对应页面,并会覆盖 app.wxss 中相同选择器。

页面注册

小程序是以 Page(Object) 构造页面独立环境,app加载后,初始化某个页面,类似于 Vue 的实例化过程,有自己的初始数据、生命周期和事件处理回调函数。

初始化数据

Vue 一样,在构造实例属性上都有一个 data 对象,作为初始数据。

Vue 中修改 data 中某个属性值直接赋值即可,而在小程序中需要使用 Page 的实例方法 setData(Object data, Function callback) 才起作用,不需要在 this.data 中预先定义,单次设置数据大小不得超过1024kb。

支持以数据路径的形式改变数组某项或对象某项属性:

// 对于对象或数组字段,可以直接修改一个其下的子字段,这样做通常比修改整个对象或数组更好
  this.setData({
    'array[0].text': 'changed data'
  })

生命周期回调函数

每个 Vue 实例在被创建时都要经过一系列的初始化过程,每一个阶段都有相应钩子函数被调用,createdmountedupdateddestroyed

vueLifecycle

对于小程序生命周期,分为 Page 的生命周期和 Component 的生命周期。

Page 的生命周期回调函数有:

  • onLoad 生命周期回调-监听页面加载
  • onShow 生命周期回调-监听页面显示
  • onReady 生命周期回调-监听页面初次渲染完成
  • onHide 生命周期回调-监听页面隐藏
  • onUnload 生命周期回调-监听页面卸载
  • onPullDownRefresh监听用户下拉动作
  • onReachBotton 页面上拉触底事件的处理函数
  • onShareAppMessage 用户点击右上角转发
  • onPageScroll 页面滚动触发事件的处理函数
  • onTabItemTap 当前是 tab 页时,点击 tab 触发

Component 的生命周期有:

  • created 在组件实例刚刚被创建时执行
  • attached 在组件实例进入页面节点树时执行
  • ready 在组件在视图层布局完成后执行
  • moved 在组件实例被移动到节点树另一个位置时执行
  • detached 在组件实例被从页面节点树移除时执行
  • error 每当组件方法抛出错误时执行
  • show 组件所在的页面被展示时执行
  • hide 组件所在的页面被隐藏时执行
  • resize 组件所在的页面尺寸变化时执行

vueLifecycle

wxs

WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。wxs 的运行环境和其他 JavaScript 代码是隔离的,wxs 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。从语法上看,大部分和 JavaScript是一样的,以下列出一些注意点和差别:

  • <wxs> 模块只能在定义模块的 WXML 文件中被访问。使用 <include><import> 时, <wxs> 模块不会被引用到对应的 WXML 文件中;
  • <template> 标签中,只能使用定义该<template>WXML 文件中定义的 <wxs> 模块;
  • Date对象,需要使用 getDate 函数,返回一个当前时间的对象;
  • RegExp对象,使用 getRegExp 函数;
  • 使用 constructor 属性判断数据类型。

组件间通信

小程序组件间通信和Vue 组件间通信很相似

父组件传值到子组件

Vue 中,父组件定义一些自定义特性,子组件通过 props 实例属性获取,也可通过 wm.$refs 可以获取子组件获取子组件所有属性和方法。

<!-- 父组件 -->
<blog-post title="A title"></blog-post>
<!-- 子组件 -->
<h3>{{ postTitle }}</h3>
export default {
  props: ['postTitle']
}

同样的,在小程序中,父组件定义一些特性,子组件通过 properties 实例属性获取,不同的是,提供了 observer 回调函数,可以监听传递值的变化。父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。

Component({
  properties: {
    myProperty: { // 属性名
      type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
      value: '', // 属性初始值(可选),如果未指定则会根据类型选择一个
      observer(newVal, oldVal, changedPath) {
        // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange'
        // 通常 newVal 就是新设置的数据, oldVal 是旧数据
      }
    },
    myProperty2: String // 简化的定义方式
  }
})

子组件传值到父组件

在Vue 中通过自定义事件系统触发 vm.$emit( eventName, […args] ) 回调传参实现。

<!-- 子组件 -->
<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>
<!-- 父组件 -->
<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

同样的,在小程序中也是通过触发自定义事件 triggerEvent 回调传参形式实现子组件向父组件传递数据。

<!-- page.wxml -->
<my-component bindcustomevent="pageEventListener2"></my-component>
// my-component.js
Component({
  methods: {
    onTap () {
      this.triggerEvent('customevent', {})
    }
  }
})

天气预报小程序

说了很多小程序开发的基础准备,下面就结合个人实际练手项目——天气预报小程序简单说明。

物料准备

从需求结果导向,天气程序首先要能获取到当前所在地天气状况,再次可以自由选择某地,知道其天气状况。这样就需要有获取天气的API和搜索地址API。

开发前物料(服务能力)准备好了,接下来就是撸小程序了!

首页获取用户信息、布局相关

布局

微信小程序的样式已支持大部分 CSS 特性,不用再去考虑太多传统浏览器兼容性问题了,布局方便直接选用 flex 布局。
比如:

/**app.wxss**/
page {
  background: #f6f6f6;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

获取用户信息

首页首次加载获取用户,通常会弹窗提示是否允许获取用户信息,用户点击允许获取授权,才能成功获取用户信息,展示用户名和用户头像等,小程序为了优化用户体验,使用 wx.getUserInfo 接口直接弹出授权框的开发方式将逐步不再支持。目前开发环境不弹窗了,正式版暂不受影响。提倡使用 button 组件,指定 open-typegetUserInfo类型,用户主动点击后才弹窗。
天气小程序获取用户头像和用户名采用的是另一种方式,使用open-data 可以直接获取用户基础信息,不用弹窗提示。

  <!-- 用户信息 -->
  <view class="userinfo">
    <open-data type="userAvatarUrl" class="userinfo-avatar"/>
    <text class="userinfo-nickname">{{greetings}},</text>
    <open-data type="userNickName"/>
</view>

城市拼音首字母锚点

上下滑动城市列表,当滑过当前可视区的城市拼音首字母,右侧字母索引栏对应的字母也会切换到高亮显示。

要满足当前的这个场景需求,首先要为城市列表的拼音首字母标题添加标志(id),当<scroll-view>滚动触发时获取各个标志位距离视窗顶部的位置,此处用到小程序 WXML 节点API NodesRef.boundingClientRect(function callback) 获取布局位置,类似于 DOMgetBoundingClientRect。距离大小为最小负数的标志位是当前刚滑过的,右侧索引栏对应字母应当高亮。

<!-- searchGeo.wxml -->
<scroll-view bindscroll="scroll" scroll-y="{{true}}">
  <!-- 城市列表... -->
</scroll-view>
Page({
  // ...
  // 城市列表滚动
  scroll () {
    wx.createSelectorQuery().selectAll('.city-list-title')
      .boundingClientRect((rects) => {
        let index = rects.findIndex((item) => {
          return item.top >= 0
        })
        if (index === -1) {
          index = rects.length
        }
        this.setIndex(index - 1)
      }).exec()
  },
  // ...
点击右侧字母索引栏的字母,城市列表自动滑动使得对应字母标题可视

满足这个需求场景,可以利用 <scroll-view> 组件的 scroll-into-view 属性,由于已有拼音首字母标题添加标志(id),只需将当前点击的字母对应的元素id滚动到可视即可。需要注意:

  • 频繁 setData 造成性能问题,在这里过滤重复赋值;
  • 由于设置了 <scroll-view> 为动画滚动效果,滚动到标志元素位置需要时间,途中可能会经过其它标志元素,不能立即设置索引焦点,要有一定延时(还没找到其它好解决方案,暂时这样)
// 点击索引条
  tapIndexItem (event) {
    let id = event.currentTarget.dataset.item
    this.setData({
      scrollIntoViewId: `title_${id === '#' ? 0 : id}`
    })

    // 延时设置索引条焦点
    setTimeout(() => {
      this.setData({
        barIndex: this.data.indexList.findIndex((item) => item === id)
      })
    }, 500)
  },

minWeather

频繁触发节流处理

频繁输入,或者频繁滚动,回调触发会造成性能问题,而其接口也有限定调用频率,这样就需要做节流处理。节流是再频繁触发的情况下,在大于一定时间间隔才允许触发。

// 节流
const throttle = function(fn, delay) {
  let lastTime = 0
  return function () {
    let nowTime = Date.now()
    if (nowTime - lastTime > delay || !lastTime) {
      fn.apply(this, arguments)
      lastTime = nowTime
    }
  }
}

具体对一些场景,比如腾讯位置服务提供的关键字搜索地址,就限定5次/key/秒,很容易就超了,可以做节流处理

Page({
  // ...
  // 输入搜索关键字
  input: util.throttle(function () {
    let val = arguments[0].detail.value
    if (val === '') {
      this.setData({
        suggList: []
      })
      this.changeSearchCls()
      return false
    }

    api.getSuggestion({
      keyword: val
    })
      .then((res) => {
        this.setData({
          suggList: res
        })
        this.changeSearchCls()
      })
      .catch((err) => {
        console.error(err)
      })
  }, 500),
  // ...
})

minWeather

对于上面城市列表滚动,获取标志元素位置也应用节流处理。

总结

小程序的基本入门学习门槛不高,小程序的设计应该借鉴了很多现在流行的框架,如果有 ReactVue 的基础会有很多似曾相识的感觉,当然,在深入的探索过程还有很多“坑”要跨越,本文只是简单的梳理,具体问题还能多看文档小程序社区,还有什么错误欢迎指正哈,完~

查看原文

desk 评论了文章 · 2018-10-23

Git 常用命令清单,掌握这些,轻松驾驭版本管理

GitHub 地址,欢迎star,查看更多整理的前端知识点

工程下载、分支的增删查改

工程下载:

  • clone 远程工程:git clone https://XXXX.git
  • fetch 远程分支到本地某分支:git fetch origin <orginname>:<localname>

分支的增删查改

  • 查看分支:git branch
  • 查看远程所有分支:git branch -r
  • 查看本地和远程所有分支:git branch -a
  • 创建分支:git branch <name>
  • 切换分支:git checkout <name>
  • 创建并切换分支:git checkout -b <name>
  • 合并某分支到当前分支:git merge <name>
  • 把分支推送到远程:git push origin <name>
  • 删除本地分支:git branch (-d | -D) <name>
  • 删除远程分支:git push origin -d <name>
  • 分支重命名:git branch (-m | -M) <oldbranch><newbranch>

注意: 不能删除当前所在本地分支。

查看提交信息日志

  • 查看分支最近一次的修改列表:git status
  • 查看分支的commit信息(倒叙排列)

    • git log 查看commit id, Author, Date, commit info
    • git shortlog 按提交者分类显示提交信息
    • git log --oneline 只输出commit id 和 commit info
    • git log --stat 查看增删查改了哪些文件

版本回退

  • 回退到上一版本:git reset --hard HEAD^
  • 回退到上上版本:git reset --hard HEAD^^
  • 回退到上上版本:git reset --hard HEAD~2
  • 回退到某个版本:git reset --hard <commit id>
  • 强制推送到远程分支:git push -f

注意:
1、HEAD 指向的版本是当前版本,^ 表示上一个版本,~N 表示上N个版本,<commit id>可简写
2、git log 可以查看<commit id>
3、git reflog 可以查看命令历史,用来回到某个未来的版本

文件的添加、提交、拉取、推送、比对、合并

  • 添加新增文件:git add README.md
  • 添加所有新增文件:git add .
  • 暂存变更文件:git stash [save "暂存备注"]
  • 恢复暂存文件:git stash pop
  • 提交变更文件:git commit -m "变更备注"
  • 拉取远程代码:git pull [origin <name>]
  • 推送到远程:git push origin <name>
  • 比对两个分支:git diff <name1><name2>
  • 比对两个分支变更的文件列表:git diff <name1><name2> --stat
  • 比对本地和远程分支:git diff <name>origin/<name>
  • 合并某个分支:git merge <name>
  • 强制覆盖本地分支:
    1、git fetch --all
    2、git reset --hard origin/<name>
    3、git pull

常用选项和其他命令

git 中部分选项解释

  • -f --force:强制
  • -d --delete:删除
  • -D --delete --force
  • -m --move:移动或重命名
  • -M --move --force
  • -r --remote:远程
  • -a --all:所有

其他命令

  • 清空工程:

$ git rm -rf .

  • 每隔X秒运行一次git pull:

$ for((i=1;i<=10000;i+=1)); do sleep X && git pull; done

  • 使用git rebase将一个feature分支变基到master分支

$ git checkout feature
$ git rebase master

配置相关

  • 查看当前配置: git config --list
  • 修改 git 的 name 和 email :

    • git config --global user.name <name>
    • git config --global user.email <email>

提示: Windows 用户可以把配置信息写入.bat文件

查看原文

desk 赞了文章 · 2018-10-23

Git 常用命令清单,掌握这些,轻松驾驭版本管理

GitHub 地址,欢迎star,查看更多整理的前端知识点

工程下载、分支的增删查改

工程下载:

  • clone 远程工程:git clone https://XXXX.git
  • fetch 远程分支到本地某分支:git fetch origin <orginname>:<localname>

分支的增删查改

  • 查看分支:git branch
  • 查看远程所有分支:git branch -r
  • 查看本地和远程所有分支:git branch -a
  • 创建分支:git branch <name>
  • 切换分支:git checkout <name>
  • 创建并切换分支:git checkout -b <name>
  • 合并某分支到当前分支:git merge <name>
  • 把分支推送到远程:git push origin <name>
  • 删除本地分支:git branch (-d | -D) <name>
  • 删除远程分支:git push origin -d <name>
  • 分支重命名:git branch (-m | -M) <oldbranch><newbranch>

注意: 不能删除当前所在本地分支。

查看提交信息日志

  • 查看分支最近一次的修改列表:git status
  • 查看分支的commit信息(倒叙排列)

    • git log 查看commit id, Author, Date, commit info
    • git shortlog 按提交者分类显示提交信息
    • git log --oneline 只输出commit id 和 commit info
    • git log --stat 查看增删查改了哪些文件

版本回退

  • 回退到上一版本:git reset --hard HEAD^
  • 回退到上上版本:git reset --hard HEAD^^
  • 回退到上上版本:git reset --hard HEAD~2
  • 回退到某个版本:git reset --hard <commit id>
  • 强制推送到远程分支:git push -f

注意:
1、HEAD 指向的版本是当前版本,^ 表示上一个版本,~N 表示上N个版本,<commit id>可简写
2、git log 可以查看<commit id>
3、git reflog 可以查看命令历史,用来回到某个未来的版本

文件的添加、提交、拉取、推送、比对、合并

  • 添加新增文件:git add README.md
  • 添加所有新增文件:git add .
  • 暂存变更文件:git stash [save "暂存备注"]
  • 恢复暂存文件:git stash pop
  • 提交变更文件:git commit -m "变更备注"
  • 拉取远程代码:git pull [origin <name>]
  • 推送到远程:git push origin <name>
  • 比对两个分支:git diff <name1><name2>
  • 比对两个分支变更的文件列表:git diff <name1><name2> --stat
  • 比对本地和远程分支:git diff <name>origin/<name>
  • 合并某个分支:git merge <name>
  • 强制覆盖本地分支:
    1、git fetch --all
    2、git reset --hard origin/<name>
    3、git pull

常用选项和其他命令

git 中部分选项解释

  • -f --force:强制
  • -d --delete:删除
  • -D --delete --force
  • -m --move:移动或重命名
  • -M --move --force
  • -r --remote:远程
  • -a --all:所有

其他命令

  • 清空工程:

$ git rm -rf .

  • 每隔X秒运行一次git pull:

$ for((i=1;i<=10000;i+=1)); do sleep X && git pull; done

  • 使用git rebase将一个feature分支变基到master分支

$ git checkout feature
$ git rebase master

配置相关

  • 查看当前配置: git config --list
  • 修改 git 的 name 和 email :

    • git config --global user.name <name>
    • git config --global user.email <email>

提示: Windows 用户可以把配置信息写入.bat文件

查看原文

赞 435 收藏 372 评论 7

desk 收藏了文章 · 2018-08-06

Magento 2.x 资料索引

desk 赞了文章 · 2018-08-06

magento2 在香港用paypal

使用Website Payments Pro Hosted Solution

现在paypal变复杂了,支付解决方案相当多,而且一些国家只能用特定的解决方案。以香港为例,不能使用payflow pro了,只能使用Website Payments Pro Hosted Solution,这在magento 1.x上使用还需要安装组件才能支持,现在2.x与paypal高度集成,已经存在Website Payments Pro Hosted Solution这个payment。但在新安装的magento2后台上很难发现这个payment,最初以为不存在,查过源代码才知道需要先选择Merchant Country为HK之后才会显示这个payment,这是挺人性化的设计,并不会搞错国家使用了不能使用的payment。

图片描述

Payment Action需要设置为Sale,这样可以自动收款。

TLSv1.2

由于paypal已经使用了TLSv1.2了,如果环境中不支持这个协议,过程就无法顺利。访问以下链接得到解决方案:
TLSv1.2 Requirement

paypal sandbox

paypal提供了很完善的测试方案,只要有正式paypal帐号,都可以建立多个paypal sandbox帐号。
https://developer.paypal.com/...
在以上地址创建sandbox商家帐号,如果是香港的务必在Country一栏选择Hong Kong,这一点很重要,使用什么支付解决方案完全取决于帐号所属地,需要跟magento2后台的Merchant Country一致。创建帐号后需要手动把帐号升级为pro

图片描述

把Classic TEST API Credentials里面的Username, Password, Signature都贴到magento2后台去,Website Payments Pro Hosted Solution就能使用。

How do I create an additional credit card number for a Sandbox account?

payment review

Website Payments Pro Hosted Solution支付完成之后,后台的订单状态应该是processing,这说明订单已经确认收款了,但却出现payment review,这时需要到登录paypal商家帐号,在收到的订单中点确认收款,然后magento2的订单才会转为processing。

在我的案例中有两个原因:

  1. 在sandbox帐号里有Payment Review选择,这个需要设为No
    图片描述
  2. 由于在我的项目中使用的支付货币是英磅,而商家帐号默认是港币,所以不能自动收款,需要添加英磅这个货币才可以,可以通过以下链接添加:
    https://www.sandbox.paypal.co...

cancel button

Website Payments Pro Hosted Solution默认没有cancel按钮,而商家帐号里可以设置cancel按钮,但设置后也不会出现。这是因为magento2使用的是iframe模式,在这个模式下cancel是不会出来的。要解决这个问题,恐怕需要修改程序了,我估计难度也不少。

IPN异常

如果paypal支付成功后order status仍然是pending payment,即有可能 Paypal IPN受阻,可以用以下方式排查:

  • 在paypal登录后到Edit Instant Payment Notification (IPN) settings页面,Notification URL:https://domain.com/paypal/ipn/index/ 并设置Receive IPN messages
  • 打开paypal debug选项,查 var/log/exception.log是否出现相关异常
  • 检查paypal IPN是否设置了disabled状态
  • 查paypal的交易历史记录以分析原因 https://www.paypal.com/hk/cgi...

测试卡号

http://www.webcreatorbox.com/...

技术支持

使用Website Payments Pro Hosted Solution的通过中出现很多问题,很多都是我无法解决的,但paypal support可以让我咨询技术上的问题,我是通过paypal support沟通多次后才能解决问题。一般一个工作天就会得到答复,有时候快的半天就有答复了。

paypal support

不用担心英文不好难以沟通,我是用中文的。

声明

以上的内容是我在实际项目中得到的经验之谈,不一定都适合于所有情况,如果无法解决问题,最好直接咨询paypal support。如果内容有错,请留言提醒。

查看原文

赞 1 收藏 1 评论 0

desk 赞了回答 · 2018-04-06

解决什么是 RESTful ?到底 REST 和 SOAP、RPC 有何区别?

关于 REST 上面已经介绍的很多了,这里对 RPC 部分做一个补充:

RPC(远程过程调用)是什么

  • 简单的说,RPC就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果。
  • RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)
  • RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)
  • RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

远程过程调用发展历程

  • ONC RPC (开放网络计算的远程过程调用),OSF RPC(开放软件基金会的远程过程调用)
  • CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构)
  • DCOM(分布式组件对象模型),COM+
  • Java RMI
  • .NET Remoting
  • XML-RPC,SOAP,Web Service
  • PHPRPC,Hessian,JSON-RPC
  • Microsoft WCF,WebAPI
  • ZeroC Ice,Thrift,GRPC
  • Hprose

早期的 RPC

  • 第一代 RPC(ONC RPC,OSF RPC)不支持对象的传递。
  • CORBA 太复杂,各种不同实现不兼容,一般程序员也玩不转。
  • DCOM,COM+ 逃不出 Windows 的手掌心。
  • RMI 只能在 Java 里面玩。
  • .NET Remoting 只能在 .NET 平台上玩。

XML-RPC,SOAP,WebService

  • 冗余数据太多,处理速度太慢。
  • RPC 风格的 Web Service 跨语言性不佳,而 Document 风格的 Web Service 又太过难用。
  • Web Service 没有解决用户的真正问题,只是把一个问题变成了另一个问题。
  • Web Service 的规范太过复杂,以至于在 .NET 和 Java 平台以外没有真正好用的实现,甚至没有可用的实现。
  • 跨语言跨平台只是 Web Service 的一个口号,虽然很多人迷信这一点,但事实上它并没有真正实现。

PHPRPC

  • 基于 PHP 内置的序列化格式,在跨语言的类型映射上存在硬伤。
  • 通讯上依赖于 HTTP 协议,没有其它底层通讯方式的选择。
  • 内置的加密传输既是特点,也是缺点。
  • 虽然比基于 XML 的 RPC 速度快,但还不是足够快。

Hessian

  • 二进制的数据格式完全不具有可读性。
  • 官方只提供了两个半语言的实现(Java,ActionScript 和不怎么完美的 Python 实现),其它语言的第三方实现良莠不齐。
  • 支持的语言不够多,对 Web 前端的 JavaScript 完全无视。
  • 虽然是动态 RPC,但动态性仍然欠佳。
  • 虽然比基于 XML 的 RPC 速度快,但还不是足够快。

JSON-RPC

  • JSON 具有文本可读性,且比 XML 更简洁。
  • JSON 受 JavaScript 语言子集的限制,可表示的数据类型不够多。
  • JSON 格式无法表示数据内的自引用,互引用和循环引用。
  • 某些语言具有多种版本的实现,但在类型影射上没有统一标准,存在兼容性问题。
  • JSON-RPC 虽然有规范,但是却没有统一的实现。在不同语言中的各自实现存在兼容性问题,无法真正互通。

Microsoft WCF,WebAPI

  • 它们是微软对已有技术的一个 .NET 平台上的统一封装,是对 .NET Remoting、WebService 和基于 JSON 、XML 等数据格式的 REST 风格的服务等技术的一个整合。
  • 虽然号称可以在 .NET 平台以外来调用它的这些服务,但实际上跟在 .NET 平台内调用完全是两码事。它没有提供任何在其他平台的语言中可以使用的任何工具。

ZeroC Ice,Thrift,GRPC

  • 初代 RPC 技术的跨语言面向对象的回归。
  • 仍然需要通过中间语言来编写类型和接口定义。
  • 仍然需要用代码生成器来将中间语言编写的类型和接口定义翻译成你所使用的编程语言的客户端和服务器端的占位程序(stub)。
  • 你必须要基于生成的服务器代码来单独编写服务,而不能将已有代码直接作为服务发布。
  • 你必须要用生成的客户端代码来调用服务,而没有其它更灵活的方式。
  • 如果你的中间代码做了修改,以上所有步骤你都要至少重复一遍。

Hprose

  • 无侵入式设计,不需要单独定义类型,不需要单独编写服务,已有代码可以直接发布为服务。
  • 具有丰富的数据类型和完美的跨语言类型映射,支持自引用,互引用和循环引用数据。
  • 支持众多传输方式,如 HTTP、TCP、Websocket 等。
  • 客户端具有更灵活的调用方式,支持同步调用,异步调用,动态参数,可变参数,引用参数传递,多结果返回(Golang)等语言特征,Hprose 2.0 甚至支持推送。
  • 具有良好的可扩展性,可以通过过滤器和中间件实现加密、压缩、缓存、代理等各种功能性扩展。
  • 兼容的无差别跨语言调用
  • 支持更多的常用语言和平台
  • 支持浏览器端的跨域调用
  • 没有中间语言,无需学习成本
  • 性能卓越,使用简单

关注 53 回答 6

认证与成就

  • 获得 0 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-04-14
个人主页被 114 人浏览