2021年3月27日星期六

从0实现一个vuex

大家知道,在开发大型vue项目时,使用vuex时不可避免的,vuex能够帮助我们在错综复杂的数据流中快速拿到自己想要的数据,提高开发效率,尽管vuex无法持久化数据,但也可以通过插件来解决该问题,总之vuex是大型项目中百利无一害的插件。

 

 

在上文我们实现了一个vue-router后,我们现在就来实现一个vuex,首先我们从vuex的原理图入手:

 

 

 

 从原理图我们可以看出,$store实例通过dispatch调用actions里的异步方法,通过commit调用mutations里的同步方法,并只能通过mutations改变state(这里插一句:非严格模式下是可以通过commit以外的方式改变state里的状态的,但在严格模式下,Vuex中修改state的唯一渠道就是执行 commit('xx', payload) 方法,其底层通过执行 this._withCommit(fn) 设置_committing标志变量为true,然后才能修改state,修改完毕还需要还原_committing变量。外部修改虽然能够直接修改state,但是并没有修改_committing标志位,所以只要watch一下state,state change时判断是否_committing值为true,即可判断修改的合法性,在严格模式下,任何 mutation 处理函数以外修改 Vuex state 都会抛出错误。)然后getters能够及时获取state中的状态并作出计算(实际上getters就是一个计算属性)

  接下来我们来简单做一个vuex的小demo,看看vuex到底实现了哪些功能:

  我们在store文件的index.js中这样写:

import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({  state: {    counter:0  },  mutations: {//同步自加的方法    add(state){      state.counter++    }  },  actions: {//异步自加的方法    add({commit}){      setTimeout(()=>{        commit('add')      },2000)    }  },  getters:{//获取乘二的值    doubleCounter(state){      return state.counter*2},//获取平方值    squareCounter(state){      return state.counter*state.counter    }  },  modules: {  }})

在Home组件中这样写:

<template>  <div >    <button @click="$store.commit('add')">counter:{{$store.state.counter}}</button>    <button @click="$store.dispatch('add')">async counter:{{$store.state.counter}}</button>    <p>double counter:{{$store.getters.doubleCounter}}</p>    <p>squareCounter:{{$store.getters.squareCounter}}</p>   <h2>这是一个Home组件</h2>   <p>我叫rick,欢迎来看我的文章:从0实现一个vuex</p>  </div></template>

那么我们的页面大致长这样:

 

 

 

点击counter可以自加,点击async counter可以延迟两秒自加,double counter读出双倍的数值,squareCounter读出平方数值

 

接下来我们把引入的vuex换成自己自制的vuex,来继续实现现有的这些功能:

 

import Vuex from './kvuex'

 

那么熟悉了原理图,设计了一个简易的vuex功能示例,接下就要来要实现我们自己的vuex啦,我们大致按照如下思路进行:

1. 首先在$store上挂载dispatch,state,getters,commmit等方法是肯定的

2. 其次要实现state的响应式,即state改变,依赖于state的所有属性都要能实现自动渲染

3. 接着实现commit和dispatch的内部方法,即为什么每次commit或dispatch都能自动调用相关的方法

4. 最后实现getters,要注意为什么这个getters能够实现只读的以及它的内部如何实现计算属性

做一个鱼骨图方便大家理解:接下来我们来逐步实现每个细节

 

 

 

1. 挂载$store

1.1 利用install和mixin

大家还记得我在实现vue-router那篇文章中的方法吗?此处我建议大家先看比较简单的vue-router的实现原理再看这篇文章哦~(见我的文章:https://www.cnblogs.com/funkyou/p/14580129.html)

我们故技重施,依然利用开发插件的方式,老规矩,复习一下vue文档:

 

 

 

为了能让所有vue组件都能通过this.$store.xxx访问到state,mutations等,那么我们就要通过全局混入的方式为vue原型上挂载一个$store的属性,全局混入用法见文档:

 

 

 

实现代码如下:

// use调用时会传入Vuefunction install(_Vue){  // 保存Vue构造函数,插件中使用  Vue=_Vue  Vue.mixin({    beforeCreate() {      // 判断当前options选项是否含有store      if(this.$options.store){        // 如果含有就在原型上挂载这个store实例        Vue.prototype.$store=this.$options.store      }    },  })}// 因为index.js是通过Vuex接收的,所以我们要这样暴露出去(实际上Vuex={Store,install,xxx})export default{Store,install}

2. 实现state响应式

2.1:借鸡生蛋

首先我们构造一个Store实例:

 

class Store{   constructor(options){        }}

 

 

其实这个options就是store中的配置项:

 

 

 

我们要想实现store中的数据响应式,能否借助现成的能实现响应式的示例来"借鸡生蛋"呢?(Vue实例此时瑟瑟发抖,并大喊你不要过来呀~)没错,Vue,就是你了,我们new 一个Vue实例,把data存放进去,这样我们的数据就能自动被Vue的defineProperty追踪并设置set和get属性,即可实现响应式:

     // data响应式处理   this._vm= new Vue({  data:{ //把state藏进$$state中       $$state:options.state  }  })

 

 

2.2: 利用get和set实现只读

我们希望我们的state是不能通过mutations以外的任何方式修改的,即实现只读,那么可以利用get和set属性对state进行设置:

  // 存取器,store.state  get state(){    console.log(this._vm);    return this._vm._data.$$state  }  set state(v){    console.error('你无法设置state的值')  }

3.实现commit

3.1判断方法

我们要从mutations中判断出当前要用的是哪个方法,并在commit内部执行这个方法,传入state的参数,但注意要在错综复杂的this环境中先把宝贵的options.mutations保存起来:

 

 //  保存mutations    this._mutations=options.mutations    // 保存actions    this._actions=options.actions    // 保存getters    this._getters=options.getters

 

 

3.2偷天换日

这里我们想用的是commit(type,payload)中的type对应的方法,那么我们能否先把这个mutations[type]方法拷贝给一个函数,再在commit方法内部执行这个函数呢?答案是可行的,这就是一种偷天换日的函数复用思想:

 commit(type,payload){    // 借用mutations[type]方法   const entry= this._mutations[type]   if(!entry){     console.error('unknown mutation type');   }  //  执行这个mutations[type]方法并传入state参数   entry(this.state,payload)  }

 

4. 实现dispatch

4.1注意参数

此处实现dispatch和mutations大致相同,但要注意actions和mutations中传入参数的不同:

mutations中:

 

 

actions中:

 

 

显然这里entry要传入的是store实例,在constructer中用this代指:

 dispatch(type,payload){    const entry=this._actions[type]    if(!entry){      console.error('unknow action type')    }    entry(this,payload)  }

 

4.2用bind留住this

但注意,此时commit内部的this还是不是我想要设置的那个store实例了?看demo:

 

 

此时的this已经完全乱套了,所以我们还需要在commit中留住this,让他执行的永远是store实例,直接写:

 //这样commit和dispatch内部的this就是当前上下文中的this,即store实例    this.commit= this.commit.bind(this)   this.dispatch= this.dispatch.bind(this)

5. 实现getters

5.1计算属性

要想实现一个只读的getters,此处我们依然选择在Vue实例中设置这个computed方法:

  // 定义computed选项和getters    const computed={}    this.getters={}   this._vm= new Vue({    data:{      $$state:options.state    },    computed  })

 

 

5.2只读属性

此处我们先保存store,随后为这个getters设置只读属性,我们可以用Object.defineProperty方法让我们能通过get读到这个方法

5.3移花接木,变无参为有参

接下来,我们想借用getters里的方法并传入state参数,但是注意:我们的getters方法是有参数的:

那么我们可以通过Object.key拿到每个方法的索引,再用一个fn保存当前索引下的方法,再在fn里传入state参数,如下:

   // 保存store    const store=this    // 遍历拿到索引key,并通过store._getters[key]找到这个方法    Object.keys(this._getters).forEach(key=>{      // 获取用户定义的getter      const fn =store._getters[key]      // 转换为computed可以使用无参数形式      computed[key]=function(){        return fn(store.state)      }      // 为getters定义只读属性      Object.defineProperty(store.getters,key,{        get:()=> store._vm[key]      })    })

 

此时我们打印这个fn,它即是:

或者

 

 

即getters中的方法,我们调用了它并完美的把state传了进去,这个方法是不是让人拍案叫绝~

 

接下来是全部源码:

//1.插件:挂载$store// 2.实现Storelet Vue  //保存Vue构造函数,插件中使用class Store{  constructor(options){   console.log(options);    //  保存mutations    this._mutations=options.mutations    // 保存actions    this._actions=options.actions    // 保存getters    this._getters=options.getters    // 定义computed选项和getters    const computed={}    this.getters={}        // 保存store    const store=this    // 遍历拿到索引key,并通过store._getters[key]找到这个方法    Object.keys(this._getters).forEach(key=>{      // 获取用户定义的getter      const fn =store._getters[key]      // 转换为computed可以使用无参数形式      computed[key]=function(){        console.log(fn);        return fn(store.state)      }      // 为getters定义只读属性      Object.defineProperty(store.getters,key,{        get:()=> store._vm[key]      })    })     // data响应式处理   this._vm= new Vue({    data:{      $$state:options.state    },    computed  })    //这样commit和dispatch内部的this就是当前上下文中的this,即store实例    this.commit= this.commit.bind(this)   this.dispatch= this.dispatch.bind(this)  }  // 存取器,store.state  get state(){    console.log(this._vm);    return this._vm._data.$$state  }  set state(v){    console.error('can not set')  }  commit(type,payload){    // 借用mutations[type]方法   const entry= this._mutations[type]   if(!entry){     console.error('unknown mutation type');   }  //  执行这个mutations[type]方法并传入state参数   entry(this.state,payload)  }  dispatch(type,payload){    const entry=this._actions[type]    if(!entry){      console.error('unknow action type')    }    entry(this,payload)  }}// use调用时会传入Vuefunction install(_Vue){  // 保存Vue构造函数,插件中使用  Vue=_Vue  Vue.mixin({    beforeCreate() {      // 判断当前options选项是否含有store      if(this.$options.store){        // 如果含有就在原型上挂载这个store实例        Vue.prototype.$store=this.$options.store      }    },  })}// 因为index.js是通过Vuex接收的,所以我们要这样暴露出去(实际上Vuex={Store,install,xxx})export default{Store,install}

 

最后看下效果:

完美实现~!如果大家想和我一起学习前端交流心得指点江山,欢迎加我的vx:shq173392531

 









原文转载:http://www.shaoqun.com/a/647732.html

跨境电商:https://www.ikjzd.com/

6pm:https://www.ikjzd.com/w/317

贝恩投资公司:https://www.ikjzd.com/w/1336


大家知道,在开发大型vue项目时,使用vuex时不可避免的,vuex能够帮助我们在错综复杂的数据流中快速拿到自己想要的数据,提高开发效率,尽管vuex无法持久化数据,但也可以通过插件来解决该问题,总之vuex是大型项目中百利无一害的插件。在上文我们实现了一个vue-router后,我们现在就来实现一个vuex,首先我们从vuex的原理图入手:从原理图我们可以看出,$store实例通过dispatc
跨境通电子商务网站:https://www.ikjzd.com/w/1329
moss:https://www.ikjzd.com/w/1653
myyearbook:https://www.ikjzd.com/w/726
备货计划及防断货库存表使用表和七段式选品风险评估表:https://www.ikjzd.com/home/103449
关于SpeedPAK奖励活动的通知 :https://www.ikjzd.com/home/121088
可比网_可比网新闻资讯_可比网报道:http://www.shaoqun.com/s/%E5%8F%AF%E6%AF%94%E7%BD%91.aspx

2021年3月26日星期五

🍖Django框架之模板层

一.两种模板方法

  • 变量相关 : {{ }}

  • 逻辑相关 : {% %}

二.注释

  • 注释是代码之母 : {# #}

三.模板语法之传值

1.Python中基本数据类型传值

def test_func(request): s = "Hello 派大星!" i = 1314520 f = 1.75 l = [1,2,3,4,5] d = {"name":"shawn","age":23} t = (2,3,4,5,5) se = {3,4,5,'rr'} b = True  # 传值方式一 : 使用字典的格式一个个传 return render(request,'test.html',{'strs':s,'ints':i,'lists':l,...}) # 传值方式二 : 使用 locals()将当前名称空间所有的变量名全部传递微页面 return render(request,'test.html',locals())
  • test.html 文件
<h1>{{ s }}</h1><h1>{{ i }}</h1><h1>{{ f }}</h1><h1>{{ l }}</h1><h1>{{ d }}</h1><h1>{{ t }}</h1><h1>{{ se }}</h1><h1>{{ b }}</h1>

image-20210318194630391

2.函数与类的传递

def test_func(request): def aa():  print("aa--->")  return 'I am aa' class Bar(object):  def cc(self):   print("Bar-->cc") B1 = Bar() return render(request, 'test.html', locals())
  • 模板层
<h1>{{ aa }}</h1><h1>{{ Bar }}</h1><h1>{{ B1 }}</h1>

image-20210318194502925

3.函数名与类名注意点

  • 传递函数名与类名都会自动加括号调用
  • 传入函数名得到的结果是函数的返回值
  • 模板语法不支持额外的传参,也就是函数无法传参

4.传值方式优缺点 :

  • 传值方式一 : 传值精确, 不会造成资源浪费
  • 传值方式二 : 传值简单, 可能造成一定的资源浪费

四.模板语法之获取值

  • django模板语法取值只能采用句点符(.),也就是点

  • 可以根据索引以及键取值,支持多个很多个点........

# views.pydef test_func(request): ll = [1,2,{"name":"shawn","age":23,"hobby":["read","study"]}] return render(request,"test.html",{"ll":ll})# 想要取出爱好read# test.html<h1>{{ ll.2.hobby.0 }}</h1>

image-20210318195629158

五.模板语法之过滤器Filter

1.过滤器说明

  • 类似于Python的内置方法
  • 将竖杠左侧的数据当做第一个参数传给右边的过滤器
  • 语法 : {{ [数据]|过滤器:可选参数 }}
  • 注意 : 竖杠左右两边没有空格
  • 过滤器参数包含空格的话需要使用引号包裹
  • 过滤器最多只能有两个参数

2.常用过滤器使用

  • django中大约60中过滤器,下面只介绍常用过滤器
# views.pydef test_func(request): s = "Hello 派大星!" i = 1314520 f = 1.75 l = [1,2,3,4,5] d = {"name":"shawn","age":23} t = (2,3,4,5,5) se = {3,4,5,'rr'} b = True w = 'aa bb cc dd ee ff' return render(request,'test.html',locals())
<!-- test.html--><p>统计长度:{{ s|length }}</p><!-- add数字相加,字符拼接--><p>加法运算:{{ i|add:1000 }}</p><p>字符串拼接:{{ s|add:'Hello 海绵宝宝' }}</p><p>拼接:{{ s|join:'@' }}</p><p>切片:{{ l|slice:'0:5:2' }}</p><p>日期格式:{{ ctime|date:'Y年-m月-d日 H时:i分:s秒' }}</p><!-- 如果第一个参数的布尔值是true则显示左边的值,否则显示default后的值--><p>默认值:{{ b|default:'哈哈' }}</p> <p>文件大小:{{ file_size|filesizeformat }}</p><!-- 截取内容包含三个点,并且算在字符个数之内-->><p>截取文本:{{ w|truncatechars:6 }}</p><!-- 截取内容包含三个点,但不算在单词个数之内,单词识别是以空格来区分的--><p>截取单词:{{ w|truncatewords:3 }}</p>

image-20210326223226444

3.转意

  • 后端使用转意
from django.utils.safestring import mark_safehtml_safe = mark_safe('<h1>你好</h1>')
  • 前端使用转意
{{ html|safe }}

六.模板语法之标签

类似于Python中的流程控制

1.for循环

{% for i in l %} <p>{{ forloop }}</p> <p>{{ i }}</p> # 循环从列表 l 中取出一个个元素{% endfor %}

我们再看看 forloop 输出的是什么:

image-20210318214321276

2.if 判断

# i = 90{% if i > 100 %} <p>is True</p>{% elif i > 80 %} <p>is two</p>{% else %} <p>is no</p>{% endif %}

image-20210318215255704

3.for 与 if 混合使用

{% for i in l %} {% if forloop.first %}  <p>is first</p> {% elif forloop.last %}  <p>is last</p> {% else %}  <p>{{ i }}</p> {% endif %}{% endfor %}

image-20210318215606748

4.empty : 空

{% for foo in request %} {% empty %}  <p>传入的数据为空,无法进行循环</p>{% endfor %}

image-20210318215938511

5.with : 取别名

{% with ll.2.hobby.0 as hb %} <p>{{ hb }}</p>    # 可以使用别名取值 <p>{{ ll.2.hobby.0 }}</p> # 也可以使用原来的方式取值{% endwith %}

image-20210318220320333

6.字典values、keys、items方法

{% for k in d.keys %} <p>{{ k }}</p>{% endfor %}{% for v in d.values %} <p>{{ v }}</p>{% endfor %}{% for kv in d.items %} <p>{{ kv }}</p>{% endfor %}

七.自定义过滤器、标签、inclusion_tag

类似于Python中的自定义函数

1.创建 templatetags 文件

  • 首先在应用下创建一个名字必须叫"templatetags"文件夹
  • 在改文件夹下创建一个任意名称的 py 文件 (例 : mytag)
  • 在该 py 文件内固定书写两行代码
from django import templateregister = template.Library()

2.自定义过滤器

  • 自定义过滤器最多只能有两个形参
from .templatetags.mytag import register# 在模板层导入自定义的过滤器时使用的是这里指定的名字@register.filter(name='myfilter') def sums(a, b): # 函数名随便起什么 return a + b # 返回两个参数的和
{% load mytag %} # 导入tag文件<p>{{ i|myfilter:100 }}</p> # 使用myfilter过滤器

image-20210318225017009

3.自定义标签

  • 自定义标签可以有多个参数
from .templatetags.mytag import register# 在模板层导入自定义的标签时使用的是这里指定的名字@register.simple_tag(name="my_tag")def my_join(a,b,c,d):   # 函数名任意 return f'{a}/{b}/{c}/{d}' # 返回参数拼接后的结果
{% load mytag %} # 导入tag文件<p>{% my_tag 'hello' 'pai' 'da' 'xing' %}</p> # 标签之后的多个参数彼此之间用空格隔开

image-20210318230441986

  • 示例二
from .templatetags.mytag import register# 在模板层导入自定义的标签时使用的是这里指定的名字@register.simple_tag(name="my_tag")def my_join(a,b):   # 函数名任意 return a+b    # 返回和
{% load mytag %}<p>{% my_tag i 100 %}</p>

image-20210318231336629

4.自定义 inclusion_tag

  • inclusion_tag 的内部原理:
  • 在HTML页面中导入写好的 inclusion_tag 并调用了
  • 触发了py文件中一个函数的执行并产生结果
  • 产生的结果通过模板语法传递给一个HTML页面进行渲染
  • 渲染完毕后又返回调用 inclusion_tag 的位置
  • 示例
from .templatetags.mytag import register@register.inclusion_tag('test.html',name='my_incl_tag') # 第一个参数是需要渲染的HTML页面def func(n): data=[] for i in range(n):  data.append(f'第{i}页') return locals()
# test.html 文件{% load mytag %}<p>{% my_incl_tag 6 %}</p>
# test2.html{{ data }}{% for foo in data %} {% if forloop.first %}  <p>{{foo}}</p> {% elif forloop.last %}  <p>{{ foo }}</p> {% else %}  <p>{{ foo }}</p> {% endif %}{% endfor %}

test.html 页面中调用了 inclusion_tag----->触发执行了一个函数产生结果并渲染到 test2.html 页面中, 渲染完又返回 test.html 页面

image-20210318235133415

八.模板的导入

类似于后端的模块, 想要什么页面,局部直接导入即可

{% include 'edit.html' %} # 直接在当前HTML文件里面显示 edit.html 文件的内容

九.模板的继承

1.模板继承的使用

  • 模板的继承首先需要选择一个模板页面, 在该页面里面使用 block 划定可以被更改的区域
# 母板页面 'home.html' 文件{% block [区域名称] %}......{% endblock %}
  • 想要继承的页面可以使用 extends 来继承某一个页面
# 子版{% extends 'home.html' %}{% block [区域名称] %}......{% endblock %}

子版继承了模板, 那么子版的整体格式与模板一样, 被 block 划分了的区域可以自己随意更改

2.模板的三个区域

  • 母板在划分区域的时候一般有三个区域
{% block css %} # css区域{% endblock %}{% block content %} # HTML区域{% endblock %}{% block js %} # js区域{% endblock %}

目的是为了让子版具有独立的css、js等,增加扩展性

  • 子版也可以继续使用母版划定了区域内的内容
{{ block.super }}

3.示例

  • 路由层
urlpatterns = [ path('admin/', admin.site.urls), path('home/', views.func), path('index/', views.func2,name='index_name'),]
  • 视图层
def func(request): return render(request,'home.html')def func2(request): return render(request,'index.html')
  • 模板层
# home.html{% block left-body %}<div > <h1>Hello, world!</h1> <p>这里是一个block划分的区域</p> <p><a href="{% url 'index_name' %}" role="button">Learn more</a></p></div>{% endblock %}# index.html{% extends 'home.html' %}{% block left-body %} <div >  <div >  <a href="#" >   <img src="../static/img/11.png" alt="...">  </a>  </div>  <div >   <a href="#" >    <img src="../static/img/11.png" alt="...">   </a>  </div> </div>{% endblock %}
  • home.html 页面

image-20210319153623274

  • index.html 页面

image-20210319153709598

十.小练习

1.需求

  • 增删改查功能

  • 將对用户增删改查的功能使用模板的继承来写

  • 代码除了模板层与之前无太大差别

2.代码实现

  • urls.py 文件
from django.contrib import adminfrom django.urls import path,re_pathfrom app01 import viewsurlpatterns = [ path('admin/', admin.site.urls), path('home/', views.home_func,name='home_name'), re_path('^edit/(\d+)', views.edit_func,name='edit_name'), re_path('^del/(\d+)', views.del_func,name='del_name'), path('insert/', views.insert_func,name='insert_name'),]
  • views.py 文件
def home_func(request): user_obj_list = models.User.objects.all() return render(request,'home.html',locals())def edit_func(request,id): if request.method == "POST":  name = request.POST.get('name')  pwd = request.POST.get('pwd')  age = request.POST.get('age')  models.User.objects.filter(id=id).update(name=name,pwd=pwd,age=age)  return redirect('home_name') user_obj = models.User.objects.filter(id=id).first() return render(request,'edit.html',{'user_obj':user_obj})def del_func(request,id): models.User.objects.filter(id=id).delete() return redirect('home_name')def insert_func(request): if request.method == "POST":  name = request.POST.get('name')  pwd = request.POST.get('pwd')  age = request.POST.get('age')  models.User.objects.create(name=name,pwd=pwd,age=age)  return redirect('home_name') return render(request,'insert.html')
  • 模板层文件
# home.html 文件##[导航栏代码]##[左侧边栏代码]##[右边内容由block划分]{% block left-body %} <div >  <div >   <h1 >用户数据</h1>   <div >    <table >     <thead>     <tr>      <th>编号</th>      <th>姓名</th>      <th>密码</th>      <th>年龄</th>      <th>操作</th>     </tr>     </thead>     <tbody>      {% for user_obj in user_obj_list %}       <tr>        <td>{{ user_obj.id }}</td>        <td>{{ user_obj.name }}</td>        <td>{{ user_obj.pwd }}</td>        <td>{{ user_obj.age }}</td>        <td>         <a href="{% url 'del_name' user_obj.id %}">删除</a>         <a href="{% url 'edit_name' user_obj.id %}">修改</a>        </td>       </tr>      {% endfor %}     </tbody>    </table>   <div >    <form action="{% url 'insert_name' %}" method="get">     <input type="submit" value="新增">    </form>   </div>   </div>  </div> </div>{% endblock %}# edit.html 文件{% extends 'home.html' %}{% block left-body %}<div ><div > <h2 >修改数据</h2> <div >  <form action="" method="post">   username:   <input type="text" name="name" value="{{ user_obj.name }}">   password:   <input type="text" name="pwd" value="{{ user_obj.pwd }}">   age:   <input type="number" name="age" value="{{ user_obj.age }}">   <input type="submit" value="提交" >  </form> </div></div></div>{% endblock %}# insert.html 文件{% extends 'home.html' %}{% block left-body %} <div > <div >  <h2 >插入数据</h2>  <div >   <form action="" method="post">   username:    <input type="text" name="name">   password:    <input type="test" name="pwd">   age:    <input type="number" name="age">    <input type="submit" value="提交" >   </form>  </div> </div> </div>{% endblock %}

image-20210319171604527

image-20210319171632069

image-20210319171716321

image-20210319171748532









原文转载:http://www.shaoqun.com/a/645728.html

跨境电商:https://www.ikjzd.com/

吉祥邮:https://www.ikjzd.com/w/1565

网易考拉海购大促:https://www.ikjzd.com/w/1052


一.两种模板方法变量相关:{{}}逻辑相关:{%%}二.注释注释是代码之母:{##}三.模板语法之传值1.Python中基本数据类型传值deftest_func(request):s="Hello派大星!"i=1314520f=1.75l=[1,2,3,4,5]d={"name":"shawn","age":23}t=
聚贸:https://www.ikjzd.com/w/1305
环球华网:https://www.ikjzd.com/w/1063
sonar:https://www.ikjzd.com/w/215
又有老板被代运营骗了!:https://www.ikjzd.com/home/132152
增加曝光率!亚马逊为自有品牌新推出"Our Brand"标签!:https://www.ikjzd.com/home/107501
社交媒体最佳实践指南,助你提升独立站曝光率:https://www.ikjzd.com/home/108988

又一家日本百货来中国开店 它会比高岛屋和伊势丹好运吗?|日本百货

  记者 | 周芳颖

  编辑 | 楼婍沁

  日本百货进入中国市场的道路总是不太顺利。

图片来源:宁波阪急微信公众号图片来源:宁波阪急微信公众号

  根据宁波阪急微信公众号消息,旗下拥有阪急阪神百货店的日本零售集团H2O Retailing在中国联合杉杉集团共同开发的百货商场"宁波阪急"将于4月开业。

  这是H2O Retailing首次在海外开设直营店,选址浙江宁波的东部新城,总建筑面积达23万方。该百货原定于2018年开业,但由于工程进度、招商,以及疫情的种种缘故曾三次延期开业。

  值得注意的是,宁波阪急此次引入了多家奢侈品牌、潮牌,以及美妆店、米其林餐厅等等,目标定位于"现代体验式时尚空间"。

  据宁波阪急微信公众号消息,其中有不少品牌将开设宁波首店,甚至浙江首店。比如,LVMH集团旗下的男士高级鞋履品牌Berluti,以及法国奢侈品牌Maison Margiela等将在宁波阪急开设浙江首店,而Jimmy Choo、思琳(CELINE)、盟可睐(Moncler)等等将开设宁波首店。

图片来源:宁波阪急微信公众号图片来源:宁波阪急微信公众号

  相较于此前进入中国的日本百货如高岛屋、伊势丹等,阪急百货并没有将一线城市作为首选。

  北京汉博商业管理有限公司上海分公司负责人杜斌告诉界面时尚,他曾从该项目相关负责人了解到,一线城市的竞争过于激烈是其未将这些城市纳入开店选址考虑的最主要原因。

  杜斌表示,阪急百货以高端奢侈品牌为主打,但在一线城市已经有太多相同定位的高端购物中心。而在毗邻一线城市的浙江、江苏省,杭州、南京等热门城市也已有杭州大厦、德基广场等大型购物综合体。选择宁波一方面是因为其各方面的综合指数不错,且无太多同类型的大型百货。另一方面,当地地价可能有相应的优惠政策。

  阪急百货对选址的谨慎考量与日本百货在中国的前车之鉴不无关系。

  伊势丹和高岛屋作为日本老牌的大型连锁百货公司,在首次进入中国时都选择上海作为起始点。

  然而,1993年就进入中国市场的伊势丹目前仅在上海、天津、成都运营三家百货公司。2014年以前,伊势丹因经营不善分别关闭了位于上海华亭、济南、沈阳的分店。

  2019年6月,高岛屋曾宣布要退出中国市场,但此后不久又撤销该决定。上海高岛屋于2012年首次开业,但自进入中国以来,上海高岛屋经营持续处于低迷状态。

  杜斌认为,高岛屋的选址在日本人、韩国人等聚居的上海长宁区古北商圈,该地区偏离核心商圈不易于揽客。此外,选品以中段价位的日系品牌为主,与中国消费者对高端奢侈品牌的需求脱离。而伊势丹虽然选址位于市中心,但门店面积不大,选品也太过于倾向日系品牌。

图片来源:宁波阪急微信公众号图片来源:宁波阪急微信公众号

  可以看出,阪急百货并不希望重蹈覆辙。

  除了将目光放在了竞争环境不激烈,且具有消费潜力的宁波,宁波阪急还致力于打造比"百货"更为丰富庞大的购物中心,并将招商重点放在奢侈品牌的"首店"上。这更易于吸引当地消费者,从而具备地标性意义。

  这对已然身陷日本零售业压力的H2O Retailing而言,或将成为一个新的增长机会。

  根据日经中文网报道,日本百货协会1月22日发布的数据显示,2020年日本全国百货商场销售额(按现有门店计算)同比减少25.7%,降至42204亿日元。这是1965年启动统计以来的最大降幅,以及近44年来的最低水平。

  但杜斌表示,宁波阪急是否能达到预期效果还有两个因素需要考量。

  一是中国仍然处于零售最寒冬的时刻,消费者的购买力和意愿未必足够,因而对日本百货而言并不是一个好的入场时机。

  此外,很多奢侈品牌会根据订货期而择期开业,从而保证开业上市的产品是最新系列。宁波阪急三番两次推后开业时间,原本商定入驻的奢侈品牌未必能如期开业。


原文转载:http://fashion.shaoqun.com/a/371732.html

跨境电商:https://www.ikjzd.com/

stadium:https://www.ikjzd.com/w/2729

亚马逊全球开店:https://www.ikjzd.com/w/1299


记者|周芳颖  编辑|楼婍沁  日本百货进入中国市场的道路总是不太顺利。图片来源:宁波阪急微信公众号  根据宁波阪急微信公众号消息,旗下拥有阪急阪神百货店的日本零售集团H2ORetailing在中国联合杉杉集团共同开发的百货商场"宁波阪急"将于4月开业。  这是H2ORetailing首次在海外开设直营店,选址浙江宁波的东部新城,总建筑面积达23万方。该百货原定于2018年开业,但由于工程进度、招
netporter:https://www.ikjzd.com/w/2132
蜜芽宝贝官网:https://www.ikjzd.com/w/1320
trax:https://www.ikjzd.com/w/1489
卖家邦:如何才能合规地快速获得大量评论?:https://www.ikjzd.com/home/14948
口述实录:老婆洗澡时小姨子跑进我卧室求欢:http://lady.shaoqun.com/m/a/82895.html
美国大选最终场!跨境行业风向如何?:https://www.ikjzd.com/home/132880

专访 CNCF 大使王炜:让云原生开发回归原始而又简单

近期,腾讯云 CODING DevOps 开源了云原生开发环境 - Nocalhost。

根据官方文档介绍,Nocalhost 来源于 No Localhost,其含义是开发者不再依赖本地计算机的编码、调试和测试过程。他是一个云原生开发环境,旨在解决云原生下开发难的问题。

例如,在 Kubernetes 环境下进行微服务开发,通常会面临以下问题:

  • 每次修改代码,都需要经过构建映像->推送映像->拉取映像->重新启动应用程序(Pod)的过程,开发的反馈循环非常长(10 分钟以上);
  • 为了开发某个微服务,必须要在本地启动整个环境和所有微服务,这带来了过度依赖本地资源的问题;
  • 开发人员只专注于他们自己的服务,随着迭代的进行,本地启动或更新完整的开发环境越来越难;
  • 微服务之间的依赖关系和启动顺序难以控制;
  • 新入职的员工一般需要 2-3 周的时间来熟悉开发环境的搭建及学习背景知识

那么,Nocalhost 到底是怎么解决以上问题的?Nocalhost 的开源,又会给 K8s 生态带来哪些影响呢?带着这些问题,我们与 Nocalhost 的设计者之一、新晋 CNCF 大使、云原生社区成员,来自腾讯云 CODING DevOps 的王炜,详细聊聊关于 Nocalhost 的产品、技术和生态。

采访嘉宾

以下为采访原文:

Q: 首先跟大家介绍一下 Nocalhost 的起源吧

王炜:Nocalhost 的起源其实是解决 CODING 自身开发难的问题。CODING 在早期已经拥抱微服务、云原生和 Kubernetes,但在我们日常开发过程中,发现 Kubernetes 虽然解决了部署和运维的问题,但同时也带来了开发难的问题。

最典型的痛处是每写几行代码,要观察代码效果或者调试,就不得不重新构建镜像->推送镜像->修改工作负载镜像版本->等待 Pod 重建的漫长过程。这个过程虽然可以用自动化的 CI/CD 来解决一部分人工手动运行问题,但其核心不变。

此外,本地全量运行 CODING 所需的资源要求非常高,早期开发人员不得不配备一台 8 核 64G 的电脑来开发,后续也尝试过为每个人都配备了一台远程的高配开发机,但开发效率仍然无法提升。

针对这种场景,我们开始探索相应的解决方案,并最终将该实践开源成为了 Nocalhost 项目。

Q:在云原生环境下,开发难除了体现在每次编码需要重新构建镜像以外,在实践中还遇到了其他痛点吗?

王炜:痛点非常多!以后端同学为例,从入职开始,熟悉和配置开发环境需要花大量的时间和精力。另外,好不容易搭建好了开发环境,需要更新微服务组件时往往出现大量组件无法启动。当然这可能更多的是应用管理问题了,目前社区也有非常好的应用模型实践。

但问题是,统一维护这套应用模型是非常吃力的,如果使用它的场景非常低频,那么问题暴露会越来越迟,最终与无人维护没有多大差别。而所有开发者的环境又是独立的,遇到问题总是自己解决而不是往上层去更新应用模型,这会进一步导致应用版本越来越老旧。

所以,我们考虑开发环境是必须要集中化管理,开发环境的部署来源只能是独立维护的应用模型,业务组协同维护并产生部署-修改循环效应,才能实现一致性的应用管理。

Q:所以 Nocalhost 会管理应用和开发环境吗?

王炜:是的。应用管理是使用外部标准,例如 Manifest 文件组合成的应用、Helm 应用和 Kustomize 应用等,它是用于拉起开发环境的标准安装方法,不同的开发者的开发环境在 Nocalhost 里的定义是开发空间(DevSpace),目前是采用 Namespace 的方式进行隔离和管理的,不同开发空间后续将支持协作开发。应用和开发空间的管理都可以在 Nocalhost 控制台来实现。

Q:Nocalhost 有哪些组件组成?

王炜:Nocalhost 主要由这几个组件组成:

  • 管理侧(面对开发环境的管理人员)

    • Nocalhost 控制台:提供开发人员管理、应用管理、开发空间管理等功能
      • Nocalhost Dep 组件:提供应用依赖管理,控制微服务依赖启动顺序
  • 用户侧(开发者)

    • nhctl-cli:Nocalhost 命令行工具,提供完整的功能
      • IDE 插件:提供 VS Code 插件和 JetBrains 插件

Nocalhost 工作示意图:

Q:Nocalhost 对开发者来说最直观的使用感受是什么?

王炜:对开发者来说,最直观的使用感受是开发过程变得非常简单,从部署开发环境到开发只需要在 IDE 插件上进行简单的四步操作:

  1. 一键拉起开发环境

  2. 点击"锤子"进入待开发组件的"开发模式"

  3. 在本地 IDE 编写代码,保存

  4. 无需重新构建镜像,新代码在远端容器直接生效

在使用 Nocalhost 进行服务开发时,屏蔽了开发所需的复杂背景知识,只需要具备语言开发基础,就能够立即进行业务代码的开发工作。

目前在 CODING 最快的实践是:刚入职的新同学,中午接到需求后,下午就已经提交了业务代码。令人兴奋的是,他面对的需求是一套由 100 多个微服务组成的系统,这一切都是建立在他不了解任何 CODING 微服务架构、开发环境、甚至是业务代码的仓库地址(Nocalhost 已提前配置好)的背景下独立完成,这在以前的开发模式下是无法想象的。

Q:比如我已有一套业务系统,怎么使用 Nocalhost ?

王炜:对于已有的业务系统,首先确认是否为 Kubernetes 标准的应用安装方式,例如 Manifest、Helm 和 Kustomize。

其次,Nocalhost 不侵入任何的业务逻辑,只需要使用声明式的配置方式提供开发参数配置即可,以开发 Istio 提供的 Bookinfo 为例。

以下是存放 Bookinfo 安装文件的 Git 仓库 :https://github.com/nocalhost/bookinfo。

该仓库的目录结构如下图所示。

其中,manifest/templates 目录包含 Bookinfo Manifest 类型的安装文件:

当有了应用之后,我们便能够为该仓库创建 .nocalhost/config.yaml 来为 Nocalhost 提供开发参数。例如,这是 Bookinfo 应用以及 productpage 服务的部分开发参数:

configProperties: version: v2application: name: bookinfo # 应用类型 manifestType: rawManifest # 应用 Manifest 的目录 resourcePath: ["manifest/templates"] ignoredPath: [] onPreInstall: [] services: # 要开发的服务名称 - name: productpage  # 要开发的服务类型  serviceType: deployment  # 声明依赖服务,将会等待依赖启动后自身才会启动  dependLabelSelector:   jobs:   - "dep-job"  containers:  - name: productpage   # 应用安装后自动端口转发   install:    portForward:     - 39080:9080   dev:   # 定义源码仓库地址   gitUrl: https://e.coding.net/codingcorp/nocalhost/bookinfo-productpage.git   # 定义开发镜像   image: codingcorp-docker.pkg.coding.net/nocalhost/dev-images/python:3.7.7-slim-productpage   # 定义进入开发容器的 bash   shell: bash   workDir: /home/nocalhost-dev   # 定义文件同步   sync:    type: send    filePattern:     - ./    ignoreFilePattern:    - ".git"    # 开发模式自动端口转发   portForward:   - 39080:9080

在该配置文件中,我们为 Nocalhost 提供了 productpage 服务的一些开发参数。最后,再通过 Nocalhost 控制台创建该应用并提供仓库地址即可。

通过以上配置,便能够实现应用无缝迁移到 Nocalhost 进行开发。

Q:Nocalhost 下一步的计划是什么?

王炜:Nocalhost 目前在 CODING 日常开发几乎已全员覆盖,但仍然有很多优化空间。

正如 Nocalhost 的 Slogan 一样,Nocalhost 的初心是让云原生开发回归原始而又简单。希望能为云原生开发环境提供探索和示范,并成为云原生生态不可缺少的一部分。

目前 Nocalhost 已进入 CNCF Landscape,后续将推进与 CNCF 更加深入的合作。

Q:能否谈谈国内的云原生发展趋势和个人看法?

王炜:根据 Gartner 研究报告指出:到 2022 年,云原生和容器化的普及率将达到 75% 以上,这意味着云原生的大趋势已成为定局。K8s 作为强大的基础设施底座,为企业应用提供了极强的生产稳定性。

但随着我们对 K8s 的使用程度越来越深,会发现 K8s 面向"工作负载"的设计在一些场景下是需要提升的。围绕着这些问题的焦点,社区不断地在为 K8s 进行插件式的扩展。CNCF Landscape 中已有接近 400 个开源产品为 K8s 提供了额外能力,这些技术方向大致被分为了数据库、消息、应用定义和镜像构建等,产品数量仍然不断上升。

K8s 生态发展至今,个人认为目前有两大方向是急需社区来解决的:第一是应用定义模型,代表有 OAM 标准和 Kubevela,该方向与 DevOps、GitOps 具有紧密联系。第二是一直被忽略的应用开发。这两个方向都是提升大规模组织开发效率的关键。

尤其是应用开发方向,目前仍然没有标准规范和优秀的实践,我相信社区也一定会有标准诞生。

最后,欢迎大家加入云原生社区参与 Nocalhost 话题讨论。另外 Nocalhost 正在招聘,也欢迎对云原生领域感兴趣的同学加入我们。









原文转载:http://www.shaoqun.com/a/644720.html

跨境电商:https://www.ikjzd.com/

picitup:https://www.ikjzd.com/w/446

邓白氏集团:https://www.ikjzd.com/w/582


近期,腾讯云CODINGDevOps开源了云原生开发环境-Nocalhost。根据官方文档介绍,Nocalhost来源于NoLocalhost,其含义是开发者不再依赖本地计算机的编码、调试和测试过程。他是一个云原生开发环境,旨在解决云原生下开发难的问题。例如,在Kubernetes环境下进行微服务开发,通常会面临以下问题:每次修改代码,都需要经过构建映像->推送映像->拉取映像->
贝恩投资公司:https://www.ikjzd.com/w/1336
oklink:https://www.ikjzd.com/w/1362
Sunrate:https://www.ikjzd.com/w/2685
亚马逊红人计划选品及操作指南:https://www.ikjzd.com/home/97410
Wish新出3大政策!一旦违规将面临高额罚款!:https://www.ikjzd.com/home/9722
谷歌宣布取消Google Shopping服务费 与亚马逊抢商家:https://www.ikjzd.com/home/126459

2021年3月25日星期四

不停喝酒不停地吐...英国的容量单位,最初都是用嘴测出来的|度量

  -

  来源: SME科技故事

  追溯英国容量单位的由来,加仑、夸脱、品脱、坎宁、蒲式耳,这些容量都建立在口上。不停地喝酒,不停地吐到容器里,吐2口是1小杯,吐4口是1杰克,吐8口是1及耳,吐16口是1大杯,吐32口是1品脱,吐64口是1夸脱,吐128口是1波特尔,吐256口是1加仑……

  英国伊丽莎白一世改革度量衡,重新厘定容量单位之间的换算关系,并且让容量与重量相结合。她规定1品脱等于20盎司,1夸脱等于40盎司,1加仑等于160盎司。1盎司则是与360颗大麦等重的水容量。


  油画《英国女王伊丽莎白一世》(约1588年),现藏于沃本修道院

  01

  古代英国人的容量单位

  追溯英国容量单位的历史,英国人过去常用的容量单位是品脱(Pint)、夸脱(Quart)、波特尔(Pottle)、加仑(Gallon);此外还有更大的容量单位,例如配克(Peck)、坎宁(Kenning)、蒲式耳(Bushel);以及更小的容量单位,例如大杯(Cup)、及耳(Gill)、杰克(Jack)、小杯(Pony)。如图1、图2所示。



  这些容量单位的换算关系如下:


  根据以上换算关系,我们可以瞧出两个要点:

  第一,传统英制容量单位之间都是倍数关系,典型的二进制;

  第二,所有英制容量单位都是建立在"口"之上的。

  什么是"口"?就是一小口。喝一小口红酒,再吐到量杯里,这个容量就是1口。不停地喝,不停地吐,一口一口地累加,吐2口是1小杯, 吐4口是1杰克,吐8口是1及耳,吐16口是1大杯,吐32口是1品脱,吐64 口是1夸脱,吐128口是1波特尔,吐256口是1加仑,吐512口是1配克,吐 1024口是1坎宁,吐2048口是1蒲式耳。

  02

  用嘴测度容量?女王恼了

  看到这儿,您肯定会觉得恶心——那么多、那么"高大上"的容量单位,竟然是通过一口一口去量得出来的。多不卫生啊。

  是的,确实不卫生。

  不卫生倒也罢了,最可怕的是不精准。您想啊,人的嘴有大有小,小芳樱桃小口,一口能吐5毫升;小强血盆大口,一口能吐50毫升。都是一口,差了十倍。即使是同一个人,每一口也不一样大:喝清爽扎啤,一口能灌半斤;喝烧刀子,一口最多半两。还是一口,又差了十倍。

  《淮南子·泰族训》有云:"寸而度之,至丈必差;铢而称之,至石必过。"一寸一寸地累积,累积到一丈,微小的误差会变成巨大的误差;一铢一铢地累积,累积到一石,微小误差会变成更加巨大的误差。

  寸和丈是古代中国的长度单位,10寸为1尺,10尺为1丈。从寸到丈,要累积100次,假如每寸有1毫米误差,那么每丈就能差出100毫米, 差不多跟您的手机一样长了。

  铢是古代中国的重量单位,24铢为1两,16两为1斤,120斤为1石(这里的"石"是"禾石"简称,读shí;如果作为容量单位,则读dàn)。从铢到石,要累积46080次,假如每铢有1克误差,每石就能差出46080克,也就是46.08千克,差不多跟一个极瘦的女模特一样重了。

  古代英国人把各种容量单位建立在"口"的基础上,假如每一口只有1毫升误差,当累积到品脱的时候,误差32毫升;累积到加仑,误差高达256毫升;如果累积到蒲式耳,误差将是2048毫升。朋友们,两千多毫升,那是什么概念?相当于三瓶红酒啊!

  公元1559年,伊丽莎白一世(上图)登上英国女王的宝座,她发现了现有容量单位既不标准也不卫生的弊端,于是下令废除用口称量的野蛮传统,并让容量与重量相结合,重新定义英国的容量单位。

  伊丽莎白一世是这样做的:她保留了品脱、夸脱、加仑等传统单位,但她让这些容量与"口"脱钩,与"盎司"结合起来。她规定,1品脱等于20盎司,1夸脱等于40盎司,1加仑等于160盎司(见下图)。


  常用英制容量单位的换算关系。1大杯=8液盎司,1品脱=2大杯,1夸脱=2品脱,1加仑=4夸脱。

  盎司本来是重量单位,1盎司等于360颗大麦加起来的重量。伊丽莎白一世让人用天平称重,在一个托盘里放入360颗成熟、饱满、晒到干透的大麦,在另一个托盘里注入同等重量的清水,再把这些托盘里清水倒进玻璃杯,玻璃杯里的清水有多少,作为容量单位的1盎司就有多少。也就是说,1盎司(上图)既是360颗大麦的重量,又是与360颗大麦等重的一杯水的容量。


  世纪苏格兰的木雕扇贝双耳酒杯(容量为1盎司)

  盎司确定了,品脱、夸脱、加仑也就确定了。稍做计算就能知道,1品脱的水与7200颗大麦等重,1夸脱的水与14400颗大麦等重;1加仑的水与57600颗大麦等重。大麦有大有小,但是将几百颗、几千颗、几万颗大麦混在一起称重,得到的会是平均重量,可以抵消颗粒之间的一些误差。

  伊丽莎白一世用上述方法改革英国容量单位,至少有以下三种好处:

  第一,新的容量单位不再需要用嘴测度,更卫生,更精准;

  第二,让容量与重量挂钩,为进一步统一度量衡奠定了基础;

  第三,大麦是当时欧洲最常见的谷物,是可应用范围内的最天然、最公平的容量测定标准,当交易双方在量度上有分歧时,不用找标准容器,不用找政府裁决,随随便便抓一把大麦,找一架天平,简简单单测量一下,就能消除分歧,这对促进市场交易非常有帮助。


  03

  英国容量统一了吗

  其实在伊丽莎白一世之前,曾经有好几位英王试图统一度量衡。

  1197年,"狮心王"理查一世颁布英国历史上第一个度量衡法令, 规定"全英格兰的所有度量衡都应使用同一标准"。

  1215年,理查一世的弟弟"无地王"约翰被迫签署《自由大宪章》,该宪章规定:"全国应有统一之度量衡。酒类、烈性麦酒与谷物之量器,以伦敦夸脱为标准;染色布、土布、锁子甲布之宽度,以织边内之两码为标准;其他衡器亦如量器之规定。"


  爱德华三世

  从1312年到1377年,爱德华三世在位期间,先后颁布《进口衣装条例》、《羊毛条例》、《葡萄酒条例》、《鲱鱼条例》、《腌鱼条例》、《家禽条例》,以及1389年理查德二世颁布《土地丈量标准条例》、《甘草、燕麦和家用面包条例》,都在重申《自由大宪章》的基础上,对全国度量衡的标准做出了详细规定。

  从1422年到1471年,亨利六世在位时,英国政府制造出一大批标准的度量衡器具,分别交给各地的市长和警察保管,当交易双方在度量衡上有分歧时,可以向官方求助,用标准器具来裁决。

  不过,裁决是需要付费的,双方交易根据商品的大小、轻重和贵重程度,向官方支付0.25便士到1便士不等的裁决费。

  从1509年到1547年,亨利八世在位时,英国政府开始强令地方官为民间度量衡器具加盖印记,凡是跟官方标准相差太多的尺子、天平和容器,强制退出市场,不许继续使用。


  英国国王亨利八世

  从1558年到1603年,英国女王伊丽莎白一世在位时,英国政府开始在各地市场上专设"市场监督员"这个职位,让市场监督员们控制物价、检查度量衡。

  但是,无论是伊丽莎白一世,还是其他英王,都没有做到真正统一英国的度量衡,甚至连容量单位都没有统一。

  最典型的表现是,各行业的容量标准不一样,同样是1加仑,量红酒的加仑就跟量啤酒的加仑有区别,量啤酒的加仑又跟量黄油的加仑有区别,量黄油的加仑则跟量谷物的加仑有很大区别。假如说1加仑红酒有4000毫升,那么1加仑大麦至少会有4500毫升。其他的容量单位,像夸脱、品脱、配克、蒲式耳等也是如此,称量液体商品的量器总是比称量固体商品的量器要小一些,结果就在英国和英国殖民地形成了"干量"和"液量"这两套标准。

  英国容量单位的统一,其实是在1824年才完成的。在那一年,英国政府再次颁布度量衡法令,废除"干量"和"液量",统一采用"英制"容量,然后才形成这样一套沿用至今的容量单位:


  原先的一些容量单位,例如坎宁、波特尔、大杯、杰克、小杯,从此退出历史舞台。

  其后,在法国牵头下,国际公制委员会成立,国际度量衡大会召开,米、千米、克、千克、毫升、公升,渐渐成为国际通用的公制单位。英国政府与时俱进,将英制容量与公制单位挂钩,规定1加仑等于4.54609188升,也就是4546.09188毫升。

  相应地,其他英制容量也都跟升和毫升建立了对应关系,虽然说换算起来稍微复杂一些,但是每个容量都清晰可靠,基本上做到了与国际接轨。

原文转载:http://tech.shaoqun.com/a/390780.html

跨境电商:https://www.ikjzd.com/

beien:https://www.ikjzd.com/w/1336

转口贸易:https://www.ikjzd.com/w/1427


-  来源:SME科技故事  追溯英国容量单位的由来,加仑、夸脱、品脱、坎宁、蒲式耳,这些容量都建立在口上。不停地喝酒,不停地吐到容器里,吐2口是1小杯,吐4口是1杰克,吐8口是1及耳,吐16口是1大杯,吐32口是1品脱,吐64口是1夸脱,吐128口是1波特尔,吐256口是1加仑……  英国伊丽莎白一世改革度量衡,重新厘定容量单位之间的换算关系,并且让容量与重量相结合。她规定1品脱等于20盎司,1
pat:https://www.ikjzd.com/w/1079
worldfirst:https://www.ikjzd.com/w/289
外贸圈:https://www.ikjzd.com/w/1083
三大策略搞定亚马逊YouTube站外引流:https://www.ikjzd.com/home/254
2020年亚马逊日本站下半年重要节日及选品推荐:https://www.ikjzd.com/home/125666
时尚电商:亚马逊和沃尔玛在2020年的发展方向!:https://www.ikjzd.com/home/113120

跨境电商资讯:外贸宣传平台有哪些(出口的

现在很多做外贸的人都非常关注 外贸企业怎么推广 ,而现在推广的途径和平台有很多,企业如果都做,成本和时间精力是一个问题,而且并不是所有的推广渠道都是有用的。今天云程网络就来为大家盘点几个有效的外贸推广渠道。 一、海外社交媒体营销 Facebook,领英等海外社交媒体营销在近几年得...