1, JavaScript的Ajax
Ajax的全称是Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求,而不需要重载(刷新)整个页面。
Ajax使用XMLHttpRequest对象取得新数据,然后再通过 DOM 将新数据插入到页面中。另外,虽然名字中包含 XML 的成分,但 Ajax 通信与数据格式无关; 这种技术就是无须刷新页面即可从服务器取得数据,但不一定是 XML 数据。
对于IE7+和其他浏览器,可以直接使用XMLHttpRequest对象,对于IE6及以前的浏览器,使用ActiveXObject对象。
使用方法如下:
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
1
2
3
4
5
6
启动请求:
xhr.open(method, url, boolean);
xhr.send();
1
2
注:
1,xhr.open参数含义:
method:请求方式,post、get等
url: 请求链接,只能向同源的url发送请求
boolean:是否异步请求,true:异步, false: 同步,默认为true
2,调用 open()方法并不会真正发送请求, 而只是启动一个请求以备发送。
3,send()方法接收一个参数,即要作为请求主体发送的数据(post方法会使用,get方法直接传null)。如果不需要通过请求主体发送数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。调用send()之后,请求就会被分派到服务器。
XMLHttpRequest对象的异步请求示例如下:
function success(text) {
console.log(text);
}
function fail(code) {
console.log(code);
}
var xhr = new XMLHttpRequest(); // 新建XMLHttpRequest对象
xhr.onreadystatechange = function () {
// 状态发生变化时,函数被回调
if (xhr.readyState === 4) { // 成功完成
// 判断响应结果:
if (xhr.status === 200) {
// 成功,通过responseText拿到响应的文本:
return success(xhr.responseText);
} else {
// 失败,根据响应码判断失败原因:
return fail(xhr.status);
}
} else {
// HTTP请求还在继续...
}
}
// 发送请求:
xhr.open('get', '/api/categories');
xhr.send(null);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
xhr的属性含义如下:
responseText: 作为响应主体被返回的文本。
responseXML: 如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存响应数据的 XML DOM 文档。
status: 响应的 HTTP 状态。
statusText: HTTP 状态的说明。
readyState :表示请求/响应过程的当前活动阶段。可取值如下。
0: 未初始化。尚未调用 open()方法。
1: 启动。已经调用 open()方法,但尚未调用 send()方法。
2: 发送。已经调用 send()方法,但尚未接收到响应。
3: 接收。已经接收到部分响应数据。
4: 完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
只要 readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件。可以利用这个事件来检测每次状态变化后readyState 的值。通常,我们只对 readyState 值为 4 的阶段感兴趣,因为这时所有数据都已经就绪。不过,必须在调用 open()之前指定 onreadystatechange事件处理程序才能确保跨浏览器兼容性。
另外,在接收到响应之前还可以调用 abort()方法来取消异步请求:
xhr.abort();
1
调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。在终止请求之后,还应该对 XHR 对象进行解引用操作。由于内存原因,不建议重用 XHR 对象。
2, jQuery的Ajax
$.ajax({
url:"",
type:"GET",
contentType: '',
async:true,
data:{},
dataType:"",
success: function(){
}
});
1
2
3
4
5
6
7
8
9
10
url 必填项,规定把请求发送到哪个 URL。
type 以什么样的方式获取数据,是get或post
contentType:发送POST请求的格式,默认值为’application/x-www-form-urlencoded;
charset=UTF-8’,也可以指定为text/plain、application/json
async 是否异步执行AJAX请求,默认为true,千万不要指定为false
data 发送的数据,可以是字符串、数组或object。如果是GET请求,data将被转换成query附加到URL上,如果是POST请求,根据contentType把data序列化成合适的格式;
dataType
接收的数据格式,可以指定为’html’、‘xml’、‘json’、'text’等,缺省情况下根据响应的Content-Type猜测。
success 可选。执行成功时返回的数据。
缺点:
是基于XHR原生开发的,目前已有的fetch可替代。本身是针对mvc的编程模式,不太适合目前mvvm的编程模式。jQuery本身比较大,如果单纯的使用ajax可以自己封装一个,不然会影响性能体验。
3,Axios
Vue2.0之后,axios开始受到更多的欢迎。其实axios也是对原生XHR的一种封装,不过是Promise实现版本。它是一个用于浏览器和 nodejs 的 HTTP 客户端,符合的ES规范。
axios具有以下特征:
从浏览器中创建 XMLHttpRequest
支持 Promise API
客户端支持防止CSRF
提供了一些并发请求的接口
从 node.js 创建 http 请求
拦截请求和响应
转换请求和响应数据
取消请求
自动转换JSON数据
PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
设置全局的 axios 默认值
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
1
2
3
注:axios 的 headers的 content-type 默认是 “application/json ”
默认情况下,axios将JavaScript对象序列化为JSON,如果是get请求,对请求参数不用做任何处理,但是如果是post请求,并且Content-Type 为application/x-www-form-urlencoded,需要使用URLSearchParams API格式化请求参数, 否则Content-Type依然是application/json
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
1
2
3
get请求,以下3中写法完全等价
axios.get('/user?id=12345&name=xiaoming')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2
3
4
5
6
7
axios.get('/user', {
params: {
id: '12345',
name: 'xiaoming'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
12
axios({
url: '/user',
method: 'get',
params: {
id: '12345',
name: 'xiaoming'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
post请求,以下2种写法完全等价
axios({
url: '/user',
method: 'post',
headers: {
'Content-Type': 'application/json'
},
data: {
id: '12345',
name: 'xiaoming'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var url = '/user';
var data = {
id: '12345',
name: 'xiaoming'
};
axios.post(url, data, {
headers: {
'Content-Type': 'application/json'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
1
2
3
4
5
6
7
8
9
10
11
12
创建实例
可以使用自定义配置新建一个 axios 实例
axios.create([config])
var instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
1
2
3
4
5
6
配置会以一个优先顺序进行合并,顺序由低到高为
1,在 node_modules/axios/lib/defaults.js 找到的库的默认值
2,实例的 defaults 属性
3,请求的 config 参数
// 使用由库提供的配置的默认值来创建实例
// 此时超时配置的默认值是 0
var instance = axios.create();
// 覆写库的超时默认值
// 现在,所有请求都会等待 2.5 秒
instance.defaults.timeout = 2500;
// 为已知需要花费很长时间的请求覆写超时设置
instance.get('/longRequest', {
timeout: 5000
});
1
2
3
4
5
6
7
8
9
10
11
12
拦截器
在请求发出之前或响应被 then 或 catch 处理前拦截它们做预处理。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
}, function (error) {
// 对请求错误做些什么
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
}, function (error) {
// 对响应错误做点什么
});
1
2
3
4
5
6
7
8
9
10
11
12
13
可以在稍后移除拦截器:
var myInterceptor = axios.interceptors.request.use(function () {/.../});
axios.interceptors.request.eject(myInterceptor);
1
2
可以为自定义 axios 实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/.../});
1
2
4, fetch
window 自带了 window.fetch 方法, 在版的 Firefox 和 Chrome 中已经提供支持,其他浏览器还有兼容性问题,要做兼容性处理。fetch 是一个 基于promise设计的low-level API,不是ajax的进一步封装,而是原生js,它注定不会像你习惯的 $.ajax 或是 axios 等库帮你封装各种各样的功能或实现.
interface GlobalFetch {
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
}
1
2
3
fetch()是一个全局的函数,返回一个promise对象。它有两个参数,第一个参数是请求的地址,第二个参数是可选,RequestInit是个对象格式如下:
interface RequestInit {
body?: any;
cache?: RequestCache;
credentials?: RequestCredentials;
headers?: HeadersInit;
integrity?: string;
keepalive?: boolean;
method?: string;
mode?: RequestMode;
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
window?: any;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
优点:
符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
更好更方便的写法
更加底层,提供的API丰富
脱离了XHR,是ES规范里新的实现方式
fetch中可以设置mode为"no-cors"(不跨域)
缺点:
fetch不支持同步请求
fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
fetch默认不会带cookie,需要添加配置项
fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
fetch没有办法原生监测请求的进度,而XHR可以
fetch的使用示例:
window.fetch(url)
.then(response => {
if (response.ok) {
//通过 response 原型上的 json 方法将 response.body 转换为 JS 对象,再返回出去
return response.json();
}
}
).then(result => {
console.log(result);
}).catch(error => {
console.log(error);
})
1
2
3
4
5
6
7
8
9
10
11
12
需要注意以下几点:
1,用 response.ok判断fetch请求是否成功
2,服务端只返回了response对象,而真正的请求结果,即 response.body,则是一个 ReadableStream。fetch 将 response.body 设计成 ReadableStream 在请求大体积文件时变得非常有用。然而,在我们的日常使用中,还是短小的 JSON 片段更加常见。而为了兼容不常见的设计,我们不得不多一次 response.json() 的调用。不仅是调用变得麻烦,如果你的服务端采用了严格的 REST 风格,对于某些特殊情况并没有返回 JSON 字符串,而是用了 HTTP 状态码(如:204 No Content),那么在调用 response.json() 时则会抛出异常。
3,Response 限制了响应内容的重复读取和转换,response .json / response.text 方法只能使用一个并且只能使用一次,同时使用两个,或使用两次都会报如下错误:
Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked
1
为什么不能使用两次?
因为数据流只能读取一次,一旦读取,数据流变空,再次读取会报错。
————————————————
版权声明:本文为CSDN博主「Sherry慈」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41480546/article/details/102805864
这里我截取的是一个图片,实际上是会动的。废话不多说,上代码。
HTML:
<canvas id="canvas"></canvas>
1
CSS:
/css reset /
body,p,div,ol,ul,li,dl,dt,dd,h1,h2,h3,h4,h5,h6,form,input,iframe,nav {
margin: 0;
padding: 0;
}
html,body {
width: 100%;
height: 100%;
}
body {
font: 14px Microsoft YaHei;
-webkit-text-size-adjust:100%;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
position: relative;
background: #000;
}
width: 100%;
height: 100%;
display: block;
opacity: .8;
}
// 音量大小,0.01-1
//宇宙
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width = window.innerWidth,
h = canvas.height = window.innerHeight,
hue = 217,
stars = [],
count = 0,
maxStars = 1100; //星星数量,默认1300
var canvas2 = document.createElement('canvas'),
ctx2 = canvas2.getContext('2d');
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width / 2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#CCC');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI 2);
ctx2.fill();
// End cache
function random(min, max) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
return Math.floor(Math.random() (max - min + 1)) + min;
}
function maxOrbit(x, y) {
var max = Math.max(x, y),
diameter = Math.round(Math.sqrt(max max + max max));
return diameter / 2;
//星星移动范围,值越大范围越小,
}
var Star = function() {
this.orbitRadius = random(maxOrbit(w, h));
this.radius = random(60, this.orbitRadius) / 10; //星星大小,值越大星星越小,默认8
this.orbitX = w / 2;
this.orbitY = h / 2;
this.timePassed = random(0, maxStars);
this.speed = random(this.orbitRadius) / 80000; //星星移动速度,值越大越慢,默认5W
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
}
Star.prototype.draw = function() {
var x = Math.sin(this.timePassed) this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) this.orbitRadius + this.orbitY,
twinkle = random(10);
if (twinkle === 1 && this.alpha > 0) {
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
this.timePassed += this.speed;
}
for (var i = 0; i < maxStars; i++) {
new Star();
}
function animation() {
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.5; //尾巴
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 2)';
ctx.fillRect(0, 0, w, h)
ctx.globalCompositeOperation = 'lighter';
for (var i = 1,
l = stars.length; i < l; i++) {
stars[i].draw();
};
window.requestAnimationFrame(animation);
}
animation();
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
开发工具与关键技术:Adobe Dreamweaver CC
作者:黄灿
撰写时间:2019.1.16
在模仿华为官方网页的练习当中我发现华为官网中有一个遮罩层是随便点击遮罩层的背景也能关闭掉遮罩层,但唯独点击内容区域不会关闭掉遮罩层。于是我开始模仿这个写案例,连内容也一模一样(因为这个练习就是要写出和华为关一样的效果或则比它更好的效果),一开始我是这样子写的(图1)
图1
class=Select_Region_bj 我给了一个灰色半透明的背景样式,后来在Javascript中写onclick事件无论这么写,点击内容区也是会关闭掉遮罩层。我百思不得其解到底怎么样写才能点击内容区不会关闭遮罩层,后来下课期间我看见我同学他写的带能点击内容区不会关闭遮罩层。我问他你是这么写的,他告诉我:“把他们分离就可以的了。”我思考了一会,脑补:分离?怎么分离?补着补着补着就补出了背景和内容区分离。分离写(图2)
图2
把背景层和内容区分开来写,不要在背景层中包裹内容,这样子点击内容区就不会关闭掉遮罩层了!
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经可以写基础组件了”,于是就关闭了vue说明文档。
实际上,插槽的概念很简单,下面通过分三部分来讲。这个部分也是按照vue说明文档的顺序来写的。
进入三部分之前,先让还没接触过插槽的同学对什么是插槽有一个简单的概念:插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题这里就点出来了,是显示不显示和怎样显示。
由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为非插槽模板和插槽模板两大类。
非插槽模板指的是html模板,指的是‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由插件自身控制;插槽模板是slot,它是一个空壳子,因为它显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置确由子组件自身决定,slot写在组件template的哪块,父组件传过来的模板将来就显示在哪块。
首先是单个插槽,单个插槽是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。
单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。
下面通过一个例子来展示。
父组件:
-
<template>
-
<div class="father">
-
<h3>这里是父组件</h3>
-
<child>
-
<div class="tmpl">
-
<span>菜单1</span>
-
<span>菜单2</span>
-
<span>菜单3</span>
-
<span>菜单4</span>
-
<span>菜单5</span>
-
<span>菜单6</span>
-
</div>
-
</child>
-
</div>
-
</template>
子组件:
-
<template>
-
<div class="child">
-
<h3>这里是子组件</h3>
-
<slot></slot>
-
</div>
-
</template>
在这个例子里,因为父组件在<child></child>里面写了html模板,那么子组件的匿名插槽这块模板就是下面这样。也就是说,子组件的匿名插槽被使用了,是被下面这块模板使用了。
-
<div class="tmpl">
-
<span>菜单1</span>
-
<span>菜单2</span>
-
<span>菜单3</span>
-
<span>菜单4</span>
-
<span>菜单5</span>
-
<span>菜单6</span>
-
</div>
最终的渲染结果如图所示:
-
-
注:所有demo都加了样式,以方便观察。其中,父组件以灰色背景填充,子组件都以浅蓝色填充。
匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次。出现在不同的位置。下面的例子,就是一个有两个具名插槽和单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。
父组件:
-
<template>
-
<div class="father">
-
<h3>这里是父组件</h3>
-
<child>
-
<div class="tmpl" slot="up">
-
<span>菜单1</span>
-
<span>菜单2</span>
-
<span>菜单3</span>
-
<span>菜单4</span>
-
<span>菜单5</span>
-
<span>菜单6</span>
-
</div>
-
<div class="tmpl" slot="down">
-
<span>菜单-1</span>
-
<span>菜单-2</span>
-
<span>菜单-3</span>
-
<span>菜单-4</span>
-
<span>菜单-5</span>
-
<span>菜单-6</span>
-
</div>
-
<div class="tmpl">
-
<span>菜单->1</span>
-
<span>菜单->2</span>
-
<span>菜单->3</span>
-
<span>菜单->4</span>
-
<span>菜单->5</span>
-
<span>菜单->6</span>
-
</div>
-
</child>
-
</div>
-
</template>
子组件:
-
<template>
-
<div class="child">
-
// 具名插槽
-
<slot name="up"></slot>
-
<h3>这里是子组件</h3>
-
// 具名插槽
-
<slot name="down"></slot>
-
// 匿名插槽
-
<slot></slot>
-
</div>
-
</template>
显示结果如图:
可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。
最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写
-
匿名插槽
-
<slot></slot>
-
具名插槽
-
<slot name="up"></slot>
但是作用域插槽要求,在slot上面绑定数据。也就是你得写成大概下面这个样子。
-
<slot name="up" :data="data"></slot>
-
export default {
-
data: function(){
-
return {
-
data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
-
}
-
},
-
}
我们前面说了,插槽最后显示不显示是看父组件有没有在child下面写模板,像下面那样。
-
<child>
-
html模板
-
</child>
写了,插槽就总得在浏览器上显示点东西,东西就是html该有的模样,没写,插槽就是空壳子,啥都没有。
OK,我们说有html模板的情况,就是父组件会往子组件插模板的情况,那到底插一套什么样的样式呢,这由父组件的html+css共同决定,但是这套样式里面的内容呢?
正因为作用域插槽绑定了一套数据,父组件可以拿来用。于是,情况就变成了这样:样式父组件说了算,但内容可以显示子组件插槽绑定的。
我们再来对比,作用域插槽和单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件是提供的模板要既包括样式由包括内容的,上面的例子中,你看到的文字,“菜单1”,“菜单2”都是父组件自己提供的内容;而作用域插槽,父组件只需要提供一套样式(在确实用作用域插槽绑定的数据的前提下)。
下面的例子,你就能看到,父组件提供了三种样式(分别是flex、ul、直接显示),都没有提供数据,数据使用的都是子组件插槽自己绑定的那个人名数组。
父组件:
-
<template>
-
<div class="father">
-
<h3>这里是父组件</h3>
-
<!--第一次使用:用flex展示数据-->
-
<child>
-
<template slot-scope="user">
-
<div class="tmpl">
-
<span v-for="item in user.data">{{item}}</span>
-
</div>
-
</template>
-
-
</child>
-
-
<!--第二次使用:用列表展示数据-->
-
<child>
-
<template slot-scope="user">
-
<ul>
-
<li v-for="item in user.data">{{item}}</li>
-
</ul>
-
</template>
-
-
</child>
-
-
<!--第三次使用:直接显示数据-->
-
<child>
-
<template slot-scope="user">
-
{{user.data}}
-
</template>
-
-
</child>
-
-
<!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
-
<child>
-
我就是模板
-
</child>
-
</div>
-
</template>
子组件:
-
<template>
-
<div class="child">
-
-
<h3>这里是子组件</h3>
-
// 作用域插槽
-
<slot :data="data"></slot>
-
</div>
-
</template>
-
-
export default {
-
data: function(){
-
return {
-
data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
-
}
-
}
-
}
结果如图所示:
以上三个demo就放在GitHub了,有需要的可以去取。使用非常方便,是基于vue-cli搭建工程。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
前言:平时写页面的时候有些样式使用完发现没过多久就忘记了,这篇文章主要是用来记录开发过程中容易忘记的CSS样式,与其总是去网上查,还不如一个一个记录下来,虽然说之前的都没有记录,但是知识的累积不论什么时候开始做都不会晚的。
首先 记录几个好用的插件网站:
layDate日期与时间组件: https://www.layui.com/laydate/
Vant移动端插件库: https://youzan.github.io/vant/#/zh-CN/intro
Element组件库: https://element.eleme.cn/#/zh-CN/component/installation
Vue.js框架: https://cn.vuejs.org/v2/guide/
Bootstrap框架: https://v2.bootcss.com/index.html
菜鸟教程官网: https://www.runoob.com/
w3school官网: https://www.w3school.com.cn/
下面是遇到的一些想累积的css样式:(内容会随时间累积的越来越多)
1、一个 div 中的内容实现上下滑动效果(而不是超出body的高以后上下滑动):overflow:auto;
简单的描述:body 中的一个 div 内,如果设置了固定的 height,而内容的总 height 超出了 div 的高,则超出的部分就会被覆盖,而想实现超出的部分变成滑动的效果而不被覆盖,则用 overflow:auto; 实现。
2、修改 前端框架封装好的css样式: border-radius: 20px!important;(注意使用英文的 ! 叹号)
简单的描述:在开发过程中经常使用一些前端框架(bootstrap,vue.js,laydate,Vant等等),在使用link导入css文件以后,发现有些css是在标签内使用内嵌的方式实现的,优先级最高,那么我们怎么修改呢?
比如:css文件中的边框弧度样式为10px:border-radius: 10px;
我们想改成20px,则在后面加上 !important 即可:border-radius: 20px!important;
这篇文章主要是以后回头复习或者忘记了的时候给我自己看的,但是如果恰好也帮助到了你,那是更加的有意义,在以后的开发过程中,该文章的内容一定会累积的越来越多
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
普通数字转会计金额格式(保留两位小数)
我们可以用数字的toLocaleString()方法将普通数字转为会计金额格式,但是这种方式无法保留两位小数(四舍五入),如果是整数或者小数长度只有一位的时候无法自动补0
例如:
思路:
利用toLocaleString()以及toFixed()先对数字进行一个转换得到最多保留了2位小数的金额,然后判断数字是为整数还是带有小数,如果带有小数则进行切割,判断小数长度为1时自动补0
// 普通数字转会计金额格式 第一种
function toThousandsFormates(num) {
// 判断传进来的数字是否为非空数字
if (!isNaN(parseFloat(num))) {
var reg = /./g
var newNum = Number(Number(num).toFixed(2)).toLocaleString()
// 判断转换后的数字是否带有小数
if (reg.test(newNum)) {
var numArr = newNum.split('.')
// 判断小数点后数字长度为1,则自动补0
numArr[1] = numArr[1].length === 1 ? numArr[1] + '0' : numArr[1]
return numArr.join('.')
} else {
// 整数直接在后面补上0.00
return newNum + '.00'
}
} else {
return ''
}
}
console.log(toThousandsFormates('0')); // 0.00
console.log(toThousandsFormates('')); // ''
console.log(toThousandsFormates(966)); // 966.00
console.log(toThousandsFormates(966.3)); // 966.30
console.log(toThousandsFormates(9669228.55)); // 9,669,228.55
console.log(toThousandsFormates(96566.56954)); // 96,566.57
经过查阅资料后,发现toLocaleString()它里面自带属性可以检查到最少保留了几位小数,不够自动补0,这样我们上面的代码其实可以更加简单,如下:
// 普通数字转会计金额格式 第二种
function toThousandsFormates2(num) {
// 判断传进来的数字是否为非空数字
if (!isNaN(parseFloat(num))) {
var newNum = Number(Number(num).toFixed(2)).toLocaleString('zh', { minimumFractionDigits: 2 })
return newNum
} else {
return ''
}
}
console.log(toThousandsFormates2('0')); // 0.00
console.log(toThousandsFormates2('')); // ''
console.log(toThousandsFormates2(966)); // 966.00
console.log(toThousandsFormates2(966.3)); // 966.30
console.log(toThousandsFormates2(9669228.55)); // 9,669,228.55
console.log(toThousandsFormates2(96566.56954)); // 96,566.57
// 结果一模一样
会计金额格式转普通数字(利用正则)
// 会计金额格式转为普通数字
function rMoney(num) {
return parseFloat(num.replace(/[^\d\.-]/g, ''))
}
console.log(rMoney('96,566.57')); // 96566.57
console.log(rMoney('966.30')); // 966.3
console.log(rMoney('9,669,228.55')); // 9669228.55
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
文章目录
rewrite在if中的用法
rewrite中break和last的用法
1.break和last在location{}外部时
2.break和last在location{}内部时
3.break和last用法总结
return的用法
rewrite的语法规则
rewrite应用实例
1.域名跳转(域名重定向)
2.http跳转https
3.跳转二级目录
4.动静态请求分离
5.防盗链配置
6.伪静态(将静态页面重写为动态)
7.多个if并用
rewrite在if中的用法
格式:if (条件判断) { 具体的rewrite规则 }
if条件判断语句由Nginx内置变量、逻辑判断符号和目标字符串三部分组成。
其中,内置变量是Nginx固定的非自定义的变量,如,$request_method, $request_uri等。
逻辑判断符号,有=, !=, ~, ~, !~, !~
!表示相反的意思,~为匹配符号,它右侧为正则表达式,区分大小写,而~为不区分大小写匹配。
目标字符串可以是正则表达式,通常不用加引号,但表达式中有特殊符号时,比如空格、花括号、分号等,需要用单引号引起来。
1
2
3
4
5
示例1:当http请求方法为post时,返回403状态码
if ($request_method = POST)
{
return 403;
}
1
2
3
4
示例2:通过浏览器标识匹配关键字,禁止IE浏览器访问
if ($http_user_agent ~ MSIE)
{
return 403;
}
1
2
3
4
限制多个浏览器:
if ($http_user_agent ~ "MSIE|firefox|Chrome")
{
return 403;
}
1
2
3
4
示例3:当请求的文件不存在时,进行重定向或return状态码等处理操作
if(!-f $request_filename)
{
rewrite 语句;
}
1
2
3
4
示例4:判断uri中某个参数的内容
if($request_uri ~ 'gid=\d{6,8}/')
{
rewrite 语句;
}
1
2
3
4
rewrite中break和last的用法
两个指令用法相同,但含义不同,需要放到rewrite规则的末尾,用来控制重写后的链接是否继续被nginx配置执行(主要是rewrite、return指令)。
1.break和last在location{}外部时
测试示例:
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
1
2
3
4
5
6
7
8
示例1:在rewrite 指令后面添加break
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
}
1
2
3
4
5
6
7
8
示例2:当break后面还有location{}的情况
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
location /2.html {
return 403;
}
}
1
2
3
4
5
6
7
8
9
10
11
2.break和last在location{}内部时
测试示例:
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
location / {
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
location /3.html
{
rewrite /3.html /b.html;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
示例1:在rewrite后面添加break
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
location / {
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
location /3.html
{
rewrite /3.html /b.html;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
示例2:在rewrite后面添加last
server{
listen 80;
server_name test.com;
root /data/wwwroot/test.com;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
location /3.html
{
rewrite /3.html /b.html;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3.break和last用法总结
1.当rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,前提是请求能匹配该location
2.当rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行
3.当rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头匹配所有location
return的用法
该指令一般用于对请求的客户端直接返回响应状态码。在该作用域内return后面的所有nginx配置都是无效的,可以使用在server、location以及if配置中,除了支持跟状态码,还可以跟字符串或者url链接。
示例1:直接返回状态码
server{
listen 80;
server_name www.test.com;
return 403;
rewrite www.test.net;
}
1
2
3
4
5
6
示例2:当return在if 判断中时
server {
.....
if ($request_uri ~ ".password|.bak")
{
return 404;
rewrite /(.*) /index.html;
}
.....
}
1
2
3
4
5
6
7
8
9
10
示例3:返回字符串
server{
listen 80;
server_name www.test.com;
return 200 "hello";
}
1
2
3
4
5
示例4:返回nginx变量
location /1.html {
return 200 "$host $request_uri";
}
1
2
3
示例5:返回url
server{
listen 80;
server_name www.test.com;
return http://www.test.com/index2.html;
}
1
2
3
4
5
示例6:返回html代码
if ($http_referer ~ 'baidu.com')
{
return 200 "<html><script>window.location.href='//$host$request_uri';</script></html>";
}
1
2
3
4
rewrite的语法规则
格式:rewrite regex replacement [flag]
rewrite 配置可以在server、location以及if配置段内生效
regex 是用于匹配URI的正则表达式,其不会匹配到$host(域名)
replacement 是目标跳转的URI,可以以http://或者https://开头,也可以省略掉$host,直接写$request_uri部分
flag 用来设置rewrite对URI的处理行为,其中有break、last、rediect、permanent,其中break和last在前面已经介绍过,rediect和permanent的区别在于,前者为临时重定向(302),而后者是永久重定向(301),对于用户通过浏览器访问,这两者的效果是一致的。
但是,对于搜索引擎爬虫来说就有区别了,使用301更有利于SEO。所以,建议replacemnet是以http://或者https://开头的,flag使用permanent。
示例1:域名跳转
location / {
rewrite /(.*) http://www.test.com/$1 permanent;
}
1
2
3
示例2:域名跳转的第二种写法
location / {
rewrite /. http://www.test.com$request_uri permanent;
}
1
2
3
示例3:文件跳转
server{
listen 80;
server_name www.test.com;
root /data/wwwroot/test.com;
index index.html;
if ($request_uri !~ '^/web/')
{
rewrite /(.) /web/$1 redirect;
}
}
1
2
3
4
5
6
7
8
9
10
错误写法1:
server{
listen 80;
server_name www.test.com;
root /data/wwwroot/test.com;
index index.html;
rewrite /(.*) /web/$1 redirect;
}
1
2
3
4
5
6
7
错误写法2:
server{
listen 80;
server_name www.test.com;
root /data/wwwroot/test.com;
index index.html;
rewrite /(.*) /web/$1 break;
}
1
2
3
4
5
6
7
rewrite应用实例
1.域名跳转(域名重定向)
单个域名的情况:
server{
listen 80;
server_name www.test.com;
rewrite /(.) http://www.test.net/$1 permanent;
}
1
2
3
4
5
多个域名的情况:
server{
listen 80;
server_name www.test.com www.test.net;
if ($host != 'www.test.net')
{
rewrite /(.) http://www.test.net/$1 permanent;
}
}
1
2
3
4
5
6
7
8
2.http跳转https
server{
listen 80;
server_name www.test.com;
rewrite /(.) https://www.test.com/$1 permanent;
}
1
2
3
4
5
3.跳转二级目录
server{
listen 80;
server_name bbs.test.com;
rewrite /(.) http://www.test.com/bbs/$1 last;
}
1
2
3
4
5
4.动静态请求分离
server{
listen 80;
server_name www.test.com;
location ~ ..(jpg|jpeg|gif|css|png|js)$
{
rewrite /(.*) http://img.test.com/$1 permanent;
}
}
1
2
3
4
5
6
7
8
第二种写法:
server{
listen 80;
server_name www.test.com;
if ( $uri ~ 'jpg|jpeg|gif|css|png|js$')
{
rewrite /(.) http://img.test.com/$1 permanent;
}
}
1
2
3
4
5
6
7
8
5.防盗链配置
server{
listen 80;
server_name www.test.com;
location ~ ^.+.(jpg|jpeg|gif|css|png|js|rar|zip|flv)$
{
valid_referers none blocked server_names .test.com
if ($invalid_referer)
{
return 403;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
http_referer表示从哪儿点击进网站的,比如从百度搜索引擎访问的
valid_referers:白名单
invalid_referer:无效的(未在白名单中定义的)
none:允许referer为空(也就是允许直接访问,未从其他站点跳转的请求)
blocked:允许来源地址不含http/https
6.伪静态(将静态页面重写为动态)
location / {
rewrite ^([^.])/topic-(.+).html$ $1/portal.php?mod=topic&topic=$2 last;
rewrite ^([^.])/forum-(\w+)-([0-9]+).html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last;
rewrite ^([^.])/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last;
rewrite ^([^.])/group-([0-9]+)-([0-9]+).html$ $1/forum.php?mod=group&fid=$2&page=$3 last;
rewrite ^([^.])/space-(username|uid)-(.+).html$ $1/home.php?mod=space&$2=$3 last;
rewrite ^([^.])/(fid|tid)-([0-9]+).html$ $1/index.php?action=$2&value=$3 last;
}
1
2
3
4
5
6
7
8
7.多个if并用
location /{
set $a 0;
if ($document_uri !~ '^/abc')
{
set $a "${a}1"; #uri不以/abc开头时,$a的值变为01
}
if ($http_user_agent ~ 'ie6|firefox')
{
set $a "${a}2"; #浏览器标识包含ie6或者Firefox时,$a的值变为012
}
if ($a = "012") #当满足前两个if判断时,重写url
{
rewrite /(.) /abc/$1 redirect;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
使用docbox定制API文档
什么是docbox
docbox的安装
克隆项目
部署方式
docbox的编写
定制logo及UI
更换代码背景色
插入自己的logo
三列改为双列
其他定制UI
在公司实习了一个月,由于业务需要,我花了大概一周时间对docbox的安装,编写,定制化等进行了详细的研究,下面给大家分享一下我的总结
什么是docbox
Docbox是一个开源的REST API文档系统。它采用结构化的Markdown文件,并生成带有导航,固定链接的两列布局。下面是官方example图片:
docbox的安装
克隆项目
直接去官网https://github.com/tmcw/docbox,然后克隆即可。
部署方式
在使用npm命令前需要下载Node.js,npm会根据package.json配置文件中的依赖配置下载安装
接着,在/content下放入.md文件,并使用 npm run build 命令,生成一个包含所需要的js代码的bundle.js文件,同时创建一个新的index.html文件
重要的就是index.html、bundle.js、/css这三个文件和文件夹
docbox的编写
在/content下放入.md文件(markdown语法俺就不说了哈……)
对/src/custom/content.js中添加需要引入的.md文件位置和以及标题
注意: /src/custom/content.js中放入的是一级标题、二级和三级标题需要在.md文件中编写。
定制logo及UI
修改/src/custom/index.js文件
修改对应标签的属性即可,定制时修改生成的index.html是没有用的,因为index.html里的标签是被动态写死的。
更换代码背景色
<div class='round-left pad0y pad1x fill-green code small endpoint-method'>
1
<div class='endpoint dark fill-blue round '>
1
插入自己的logo
修改/src/components/app.js文件
三列改为双列
docbox默认情况下是显示三列布局,但我们可以在app.js下进行修改使之默认为双列布局。将下图的1改为2即可切换双列模式
其他定制UI
像下图一样,我们可以修改并填写代码得到自己想要的页面样式,比如说我在最上方加了一个固定位置的区域,然后可以在这个区域添加相应的超链接等。
app.js里可以找到图中对应的标签和js代码,docbox支持多种语言切换,我们在需要的地方加入我们想要加入的标签,并在/css文件夹中对相应的css文件添加样式就可以定制我们想要的UI啦!!!
下面给大家列出一些用docbox定制API文档的网站
Mapbox API文档
Mapillary的API文档和Tiles文档
HYCON 8th
Wall
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
说明:本文基于thymeleaf3.x
在做后台系统时多多少少都会遇到下拉选回显的问题,本次就总结一下如何利用thymeleaf简单快速的进行下拉选的回显。
两种情况:
1、下拉选的数据固定死了的情况下?
利用 th:field="${要选中的option的value值}" 属性,如下
<select id="bookKind" name="bookKind" th:field="${book.bookKind}" class="form-control">
<option value="">请选择书的种类</option>
<option value="1">编程语言</option>
<option value="2">数据库</option>
<option value="3">操作系统</option>
<option value="4">办公软件</option>
<option value="5">图形处理与多媒体</option>
</select>
book是请求域中的实体类,当${book.bookKind}的值和 option 的 value值匹配上后,该option就会被选中。
怎么样是不是很简单?如果是用ajax的话,还要先获取所有的option,循环遍历,判断value值是否相等,设置selected属性值为true,跳出循环,这一系列操作,thymeleaf一个属性值就搞定,所以孰轻孰重您就看着来吧!哈哈!
2、下拉选的数据没固定死时?
两个属性 th:each="bookKind : ${bookKinds}" th:selected="{bookKind} == ${book.bookKind}" 搞定,如下所示
<select id="bookKind" name="bookKind" class="form-control">
<option th:each="bookKind : ${bookKinds}" th:selected="{bookKind} == ${book.bookKind}"
th:value="${bookKind}" th:text="${bookKind}"></option>
</select>
解释一下,先th:each遍历,*{bookKind}代表遍历出来的元素,判断与点击的者一栏的bookKind值是否一样,如果一样th:selected的值就为true,然后th:value 设置option的value 值,th:text 设置option的文本值。
试想一下,如果是用ajax会怎么样?1、先后台获取数据后,循环append(html标签) 2、再获取到当前记录的这列属性值,再获取到 1 中循环设置的option,在比对value值,设置选中,break等。而且第一个ajax还要整成同步的,不然 2 中可能获取不到 1 中的option元素。
最后说明:如果恰巧能解决你的问题,那就动一动您的小手,点个赞或者评论一下,让我看到你们,您的点赞或评论将会持续带给我不懈的动力!!!come on baby!Let's go!
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
什么是编程式的导航
除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。
想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
HTML代码
<p @click="$router.push('/test/emitView')">跳转1</p>
<p @click="$router.push({path: '/test/propsView'})">path: '/test/propsView'</p>
<p @click="test">带参数的跳转</p>
<p @click="test1">提供了path,params会被忽略</p>
<p @click="$router.push({path: /test/propsView/${userId}
})">
url变为/test/propsView/123
</p>
<p @click="$router.push({path: '/test/propsView', query: {plan: 'private'}})">
带参数的url变为/test/propsView?plan=private
</p>
Script中代码
test () {
this.$router.push({
name: 'routerView',
params: {userId: this.userId, test: 333},
})
console.log(this.$route)
console.log(this.$route.params)
},
test1 () {
this.$router.push({ // 如果提供了 path,params 会被忽略
path: 'routerView',
params: {userId: this.userId, test: 333},
})
console.log(this.$route)
console.log(this.$route.params)
},
router.replace(location, onComplete?, onAbort?)
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
router.go(n)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 如果 history 记录不够用,则无反应
router.go(-100)
router.go(100)
router.back()
在浏览器记录中后退一步
router.forward()
在浏览器记录中前进一步
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
蓝蓝设计的小编 http://www.lanlanwork.com