1.过滤器
- 过滤器的格式,由'管道'符进行分割,'管道'符|的前边是原数据,后边是过滤器名.
- 过滤器的作用:根据原本的数据过滤成一个新数据.
- 过滤器的定义有两种方式,第一种是全局定义,第二种是局部定义.
全局定义过滤器
例:
<div id="app">
<!-- 原数据输出 i am tom -->
<p>{{msg}}</p>
<!-- msg是原数据 | upper是过滤器名 -->
<!-- 原数据过滤后输出 I am tom -->
<p>{{msg | upper}}</p>
</div>
<script>
// 全局过滤器的结构,利用.filter关键字,第一个参数是自定义的过滤器名,
// 第二个参数是一个回调函数,回调函数的第一个参数是原数据.
Vue.filter('upper', function (value) {
// 截取原数据的第一个字符并转换为大写字母 + 从第一个字符之后截取的字符串.
return value.slice(0, 1).toUpperCase() + value.slice(1)
});
new Vue({
el: "#app",
data: {
msg: "i am tom"
},
})
</script>
<!-- 带参数的过滤器 -->
例:
<div id="app">
<!-- 这里过滤器传进来的参数是upper -->
<!-- 根据js中写的逻辑那么就输出 I am jerry -->
<p>{{msg | selectCase('upper')}}</p>
</div>
<script>
// 'selectCase'是自定义过滤器名,第二个参数是一个回调函数,
// 回调函数的第一个参数是原数据,第二个参数这里做条件判断用.
Vue.filter('selectCase', function (value, select) {
//如果回调函数中第二个参数 == upper 就将原数据中的第一个字符转换为大写字母,
//反之如果回调函数中第二个参数 == lower 就将原数据中的第一个字符转换为小写字母
if (select == 'upper') {
return value.slice(0, 1).toUpperCase() + value.slice(1)
} else if (select == 'lower') {
return value.slice(0, 1).toLowerCase() + value.slice(1)
}
});
new Vue({
el: "#app",
data: {
msg: "i am jerry"
},
})
</script>
<!-- 多个过滤器可以连用 -->
例:
<div id="app">
<!--多个过滤器可以连用-->
<!--
第一次过滤:原数据 -> I am jerry
第一次过滤:基于上次过滤结果 -> i am jerry
最后一次过滤后输出 i am jerry-How are you
-->
{{msg | upper | selectCase('lower') | str}}
</div>
<script>
// 过滤器1
Vue.filter('upper', function (value) {
return value.slice(0, 1).toUpperCase() + value.slice(1)
});
// 过滤器2
Vue.filter('selectCase', function (value, select) {
if (select == 'upper') {
return value.slice(0, 1).toUpperCase() + value.slice(1)
} else if (select == 'lower') {
return value.slice(0, 1).toLowerCase() + value.slice(1)
}
});
// 过滤器3
Vue.filter('str', function (value) {
return value + "-How are you"
});
new Vue({
el: "#app",
data: {
msg: "i am jerry"
},
})
</script>
局部定义过滤器
例:
<div id="app">
<!-- msg原数据 lower过滤器 输出 i am tom -->
<p>{{msg | lower}}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "I am tom"
},
// 局部定义过滤器
// 跟 el data平级 定义一个filters
filters: {
// lower是自定义过滤器名,后面跟上一个函数,value同样是原数据.
'lower': function (value) {
return value.slice(0, 1).toLowerCase() + value.slice(1)
}
}
})
</script>
2.自定义指令
- 除了使用系统提供的预定义指令,我们还可以使用自定义指令.
- 自定义指令的方式也是两种,全局定义和局部定义.
<!-- 全局定义自定义指令 -->
<div id="app">
<!-- 加载页面input框自动获取焦点 -->
<input type="text" v-focus>
</div>
<script>
// 自定义指令的关键字是.directive;
// 第一个参数是自定义指令名,要取消v-,在标签上把v-加上;
// 第二个参数是一个对象,对象的内部是自定义指令运行的阶段,阶段key对应一个函数;
// 函数的第一个参数是元素节点,第二个参数是一些必要的属性参数,在函数内部来进行自定义指令的逻辑.
Vue.directive('focus',{
inserted:function (el, binding) {
el.focus();
}
});
new Vue({
el: "#app",
data: {}
})
</script>
<!-- 全局定义自定义指令 -->
<div id="app">
<!-- 黄色 -->
<div v-color>猜我的颜色</div>
<!-- 红色 -->
<div v-color="color">猜我的颜色</div>
</div>
<script>
// bind和inserted是我们自定义指令的两个常用的阶段.
// bind执行在inserted之前,是在指令绑定到元素时执行,或者叫编译这个指令时执行.
// 他们的运行类似于事件的机制,就是当指令绑定到dom时,执行bind后边的函数.
// 当将原dom对象用Vue编译好以后(例如v-if,v-for都需要用Vue编译才能在正常浏览器中显示).
// vue将编译后的对象,替换掉原节点,替换好之后,触发inserted后边的函数,
// vue的运行过程,是先熏染页面,然后再获取页面的结构进行编译.
// 编译成的对象叫做虚拟dom.
// 编译完成真实的dom对象后,替换掉页面的dom结构.
/* 总结:bind阶段:指令初次绑定到dom元素时,调用bind后面的函数(只调用一次)
inserted阶段:Vue将原dom对象编译好,再替换掉原dom元素,再调用inserted后面的函数. */
Vue.directive('color',{
//inserted执行在bind之后
inserted(el,binding){
alert("inserted");
el.style.backgroundColor="yellow";
el.style.backgroundColor=binding.value;
console.log(binding.value); // red
},
// bind执行在inserted之前
bind:function (el, binding) {
alert("bind");
el.style.backgroundColor="yellow";
}
});
new Vue({
el: "#app",
data: {
color:"red"
}
})
</script>
<div id="app">
<!--局部定义自定义指令-->
<input type="text" v-fo>
</div>
<script>
new Vue({
el: "#app",
data: {},
// 局部定义自定义指令
directives:{
'fo':{
inserted:function (el, binding) {
el.focus();
}
}
}
})
</script>
3.computed (计算属性关键字)
- 可以使用computed属性,替换掉{{ }}中的复杂方法.
- computed对应一个对象,
对象的内部是很多个计算属性,
计算属性的格式是键值对结构,值是一个函数,函数内部返回一个值,
这个值,就是键值对结构的key(msg),
计算属性虽然是一个函数,但不用执行,用法跟data属性中的用法一致.
<!-- 简单的例子开始 -->
例1:
<div id="app">
<!-- {{}}中的复杂方法 输出 dlrow olleh -->
<p>{{ message.split('').reverse().join('') }}</p>
<!-- 使用computed属性替换掉的 输出 dlrow olleh -->
<p>{{ myMsg }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
message: "hello world"
},
// 使用computed属性,替换掉{{}}中的复杂方法
computed: {
myMsg: function () {
//以空字符串截取成一个数组再反转过来以空字符串转换成字符串
return this.message.split('').reverse().join('')
},
},
</script>
<!--加法运算的功能,p标签时两个input框的计算结果,并且input框改变时,同时改变p标签结果-->
例2:
<div id="app">
<!-- 因为输入的是字符串所以要转换为number类型再进行运算 -->
<input type="text" v-model.number="input1"> +
<input type="text" v-model.number="input2"> =
<!--equal是使用computed属性计算出来的 -->
<span>{{ equal }}</span>
---
<!--equal2是通过methods函数内部逻辑计算出来的,运算结果同上-->
<span>{{ equal2() }}</span>
</div>
<script>
new Vue({
el: "#app",
data: {
input1: 0,
input2: 0
},
// 使用computed属性,替换掉{{}}中的复杂方法
computed: {
equal: function () {
return this.input1 + this.input2
},
},
// 在函数里也可以进行逻辑运算
methods: {
equal2:function () {
return this.input1 + this.input2
},
}
</script>
<!--需求:我们希望把数据大于0的项显示出来,把小于0的项过滤掉-->
例3:
<div id="app">
<ul>
<li v-for="item in changedArr">{{item}}</li>
</ul>
</div>
<script>
new Vue({
el: "#app",
data: {
arr: [1, 2, 3, 4, 5, -1, -2, -3]
},
// 使用computed属性,替换掉{{}}中的复杂方法
computed: {
// 过滤后的数组
changedArr: function () {
return this.arr.filter(function (item, index) {
//该函数返回结果是true的项组成的新数组
return item > 0
})
}
},
</script>
总结
- 计算属性跟filter属性的区别 :
- 过滤属性一般用于将一个值转化为另一个值在同一个位置上输出,
computed是执行某一些计算,计算结果可以在任何位置数据. - 有一些指令如v-for不可以使用filter过滤器,可以用computed属性代替.
- computed和methods属性的区别 :
- computed性能高,computed只计算一次,然后将值缓存下来.
- 而methods函数,在页面上输出多个的话,每一次都要进行内部函数的逻辑.
- vue的作者强烈建议多使用computed
4.Vue组件
Component 组件
组件的定义和注册
- 组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。
1. 写法一:使用Vue.extend方法定义组件,使用 Vue.component方法注册组件
<div id="app">
<!-- 这里的标签必须与全局注册的标签一致 -->
<tmp1></tmp1>
</div>
<script type="text/javascript">
// 1. 写法一:使用Vue.extend方法定义组件,使用 Vue.component方法注册组件
//定义组件
var tmp1 = Vue.extend({
template:"<div><a href='#'>注册</a></div>"
});
//全局注册组件
Vue.component('tmp1',tmp1);
new Vue({
el:"#app",
data:{}
});
</script>
2.写法二: 使用 Vue.component方法定义注册组件一步到位
<div id="app">
<!-- 这里的标签必须与全局注册的标签一致 -->
<tmp2></tmp2>
</div>
<script type="text/javascript">
//定义和注册组件一步到位
Vue.component('tmp2',{
template:"<div><a href='#'>tmp2</a></div>"
})
new Vue({
el:"#app",
data:{}
});
</script>
3.写法三:将组件内容定义到template模板中
<!--将组件内容定义到template模板中 -->
<template id="tmp3">
<div><a href='#'>tmp3</a></div>
</template>
<div id="app">
<tmp3></tmp3>
</div>
<script type="text/javascript">
Vue.component('tmp3',{
template:"#tmp3"
})
new Vue({
el:"#app",
data:{}
});
</script>
4.写法四:将组件内容定义到类型为 x-template的script模板中
<!-- 将组件内容定义到类型为 x-template的script模板中 -->
<script type="x-template" id="tmp4">
<div><a href='#'>tmp4</a></div>
</script>
<div id="app">
<tmp4></tmp4>
<login-To></login-To>
</div>
<script type="text/javascript">
Vue.component('tmp4',{
template:"#tmp4"
})
// 命名时的注意点:使用驼峰形式命名时,需要把view层的标签改成中划线连接的形式
Vue.component('loginTo',{
template:"#tmp4"
})
new Vue({
el:"#app",
data:{}
});
</script>
组件中注册子组件
<!-- 定义组件id为tmp的组件模板 -->
<template id="tmp">
<div>
Hello World
<!-- login组件必须放在内部设置一个根节点 -->
<!-- template不算根节点 -->
<login></login>
</div>
<!-- 在account组建中使用login子组件 -->
</template>
<div id="app">
<account></account>
</div>
<script type="text/javascript">
//定义和注册account组件
Vue.component("account",{
template:"#tmp",
//在account组件中定义和注册一个login子组件
//这里面的组件是局部组件
components:{
'login':{
template:"<p>登录</p>"
}
}
})
new Vue({
el:"#app",
data:{}
});
</script>
组件的独立作用域
<!-- 组件模板 -->
<template id="temp">
<div @click = "login()">
Hello World
<!-- 定义的子组件只能在父组件中使用,否则不管用,子组件的事件不会冒泡到父元素身上 -->
<login @click = "login()"></login>
<!-- .stop禁止事件冒泡到父元素身上 -->
<button @click.stop = "login()">点我</button>
</div>
</template>
<div id="app">
<!-- 使用组件 -->
<account></account>
</div>
<!--子组件只能在父组件的模板中使用,
组件跟组件的作用域是相互独立的
组件跟组件所有的属性都是独立的,包括methods,filters,directives,data
这也是局部定义属性的意义.
-->
<script type="text/javascript">
//定义和注册组件
Vue.component("account",{
template:"#temp",
components:{
'login':{
template:"<button>登录</button>"
}
},
// 注意:原来在new Vue()中定义的data是一个对象
// 但是在组件中定义的data是一个方法,并且在这个方法中一定要return一个对象
data:function(){
return {
msg: "我是account组件中的msg!"
};
},
//定义一个方法
methods:{
login:function(){
alert(this.msg);
}
}
});
new Vue({
el:"#app",
data:{}
});
</script>
5.Vue.js中的AJAX请求
- http协议
Vue可以借助于vue-resource或者axios来实现AJAX请求(axios不支持jsonp),
同源策略:A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个 相同"。
协议相同
域名相同
端口相同
例:http://xxx.com:80/login.html
协议:http
域名:xxx.com
端口:80
-
http请求报文
浏览器与服务器数据交互是遵循http协议的,当浏览器要访问服务器的时候,浏览器需要将相关请求数据提交给服务器(例如:浏览器信息,url地址,参数等),通常是通过请求报文来提交的
请求报文的格式分为:
1、请求报文行 2、请求报文头 3、请求报文体
-
http响应报文
当浏览器请求服务器的时候,服务器需要将数据返回给浏览器,这种数据是通过响应报文响应回浏览器的
响应报文的格式分为:
1、响应报文行 2、响应报文头 3、响应报文体
- jsonp跨域原理
就是利用<script>标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。
<script>
function test(data) {
console.log(data);
}
</script>
<script src="http://vue.studyit.io/api/jsonp?callback=test">
</script>
- cors
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
- vue-resource
Vue与后台Api进行交互通常是利用vue-resource(其中的一种方法)来实现的,本质上vue-resource是通过http来完成AJAX请求响应的
get请求地址:http://vue.studyit.io/api/get...
post请求地址:http://vue.studyit.io/api/add... 参数:name:'奔驰'
jsonp请求地址:http://vue.studyit.io/api/jsonp
- vue-resource GitHub 地址:https://github.com/pagekit/vu...
- vue-resource Http请求api参考(主要看这个):https://github.com/pagekit/vu...
- axios npm文档:https://www.npmjs.com/package...
-
vue结合vue-resource写法步骤
1、通过 https://cdn.jsdelivr.net/vue.resource/1.2.1/vue-resource.min.js 下载到vue-resource文件 2、在html页面中通过script标签导入vue-resource.min.js 文件后,就会自动的在Vue对象实例上初始化 $http 3、使用 // 全局Vue对象写法 Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback); Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback); // 在Vue对象中的写法 this.$http.get('/someUrl', [options]).then(successCallback, errorCallback); this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
-
vue-resource get请求
写法格式: this.$http.get('请求的url', [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 成功回调函数参数对象主要属性说明: 1、url : 请求的原始url 2、body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 3、其他属性请看文档 举例: this.$http.get('http://vuecms.ittun.com/api/getlunbo?id=1').then(function(res){console.log(res.body)}, function(err){//err是异常数据});
-
vue-resource post请求
写法格式: this.$http.post('请求的url',[可选参数请求报文体对象body,使用{}传参], [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 成功回调函数参数对象主要属性说明: 1、url : 请求的原始url 2、body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 3、其他属性请看文档 注意点: $http.post()方法中的第二个参数固定写成:{emulateJSON:true},否则可能造成服务器无法接收到请求报文体中的参数值 举例: this.$http.post('http://vuecms.ittun.com/api/adddata?id=1' //请求的url ,{content:'hello'} //请求报文体中传入的参数对象,多个使用逗号分隔 ,{emulateJSON:true} //固定写法,保证服务器可以获取到请求报文体参数值 ).then(function(res){console.log(res.body)}, function(err){//err是异常数据});
-
vue-resource jsonp请求
jsonp请求主要用来解决ajax跨域请求问题,使用jsonp实现跨域首先要保证服务器api支持jsonp请求的格式 写法格式: this.$http.jsonp('请求的url', [可选参数对象,使用{}传参]).then(成功回调函数, 失败回调函数); 成功回调函数参数对象主要属性说明: 1、url : 请求的原始url 2、body: 响应报文体中的数据(我们通常用这个属性获取服务器返回的数据) 3、其他属性请看文档 举例: this.$http.jsonp('http://vuecms.ittun.com/api/getlunbo?id=1').then(function(res){console.log(res.body)}, function(err){//err是异常数据});
6.产品案例 (完善-利用vue-resource完成AJAX版本)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
text-decoration: none;
}
.title {
margin: 0 auto;
width: 100px;
height: 100px;
}
h2 {
text-align: center;
margin: 50px;
font-family: "宋体";
color: #333;
font-size: 26px;
}
a {
color: #d8505c;
}
table {
border: 1px solid #999;
border-collapse: collapse;
width: 800px;
margin: 20px auto;
text-align: center;
}
table th {
background: skyblue;
border: 1px solid #999;
padding: 5px;
}
table td {
border: 1px solid #999;
padding: 5px;
}
.add {
width: 800px;
margin: 20px auto 0 auto;
text-align: center;
font-size: 0;
}
.add input {
outline: none;
border: none;
width: 200px;
height: 30px;
border: 1px solid #ccc;
padding-left: 10px;
}
.add .addInp {
border-right: transparent;
}
.add .search {
margin-top: 10px;
}
.add button {
border: none;
width: 50px;
height: 32px;
background: skyblue;
color: #FFF;
vertical-align: top;
}
</style>
<!-- 引入Vue.js文件 -->
<script src="./js/vue.js"></script>
<!-- https://cdn.jsdelivr.net/vue.resource/1.2.1/vue-resource.min.js 下载到vue-resource文件 -->
<script src="./js/vue-resource.js"></script>
</head>
<body>
<div id="app">
<div class="add">
<h2>产品管理</h2>
<!-- v-focus 挂载上自定义指令 -->
<input type="text" class="addInp"
v-model.trim = "value"
placeholder="请输入产品名称"
@keyup.enter = "add()"
v-focus
>
<!-- 点击添加按钮调用add函数添加数据 -->
<button @click = "add()">添加</button><br>
<!-- 筛选数据列表 -->
<input type="text" class="search"
placeholder="请输入筛选内容"
v-model = "filterValue"
>
</div>
<table>
<thead>
<th>编号</th>
<th>名称</th>
<th>创建时间</th>
<th>操作</th>
</thead>
<tbody>
<!-- 用v-for遍历arr数组中的每一个对象,并把相应数据渲染到页面上展示 -->
<tr v-for = "(item,index) in changeArr">
<td>{{index + 1}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime | timefmt}}</td>
<!-- 点击删除调用del函数删除加数据 注意:需要传入参数index -->
<td><a href="javascript:;" @click = "del(item.id)">删除</a></td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
Vue.filter('timefmt',function(value) {
value = new Date(value);
var year = value.getFullYear();
var month = value.getMonth() + 1;
var day = value.getDate();
var hour = value.getHours();
var minute = value.getMinutes();
var second = value.getSeconds();
//二次处理
day = day<10?"0"+day:day;
hour = hour<10?"0"+hour:hour;
minute = minute<10?"0"+minute:minute;
second = second<10?"0"+second:second;
return year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second;
});
new Vue({
//规定作用域
el:"#app",
//放置所有数据
data:{
arr:[
// {name: '宝马',ctime: new Date},
// {name: '奔驰',ctime: new Date},
// {name: '奥迪',ctime: new Date}
],
//用于获取input中的数据
value:"",
filterValue:""
},
created:function(){
this.getData();
},
methods:{
//渲染数据到页面上
getData:function(){
//确定url
var url = "http://vue.studyit.io/api/getprodlist";
this.$http.get(url).then(function(res){
//提取数据
var data = res.body;
//判断获取到的数据是否正确
if(data.status != 0){
alert("获取数据失败");
return;
}
//将获取到的数据放入到data中
this.arr = data.message;
},function(err){
console.log(err);
});
},
//添加数据
add:function(){
//非空判断
if(this.value == ""){
alert("输入内容不能为空!");
return;
}
// this指的是Vue实例对象
// 查重复数据
for(var i=0;i<this.arr.length;i++){
//如果数据中的每一项的名称跟输入的名称一样的时候提醒已添加过,
//并及时return掉不在执行后续代码
if(this.arr[i].name == this.value){
alert('此条数据你已经添加过了!')
return;
}
}
// 确定url
var url = "http://vue.studyit.io/api/addproduct";
//post请求
this.$http.post(url,{name:this.value},{emulateJSON:true}).then(function(res){
//先提取数据
var data = res.body;
if(data.status == 0){
alert(data.message);
// 重新调用获取数据方法用于刷新数据
this.getData();
}else {
alert("数据添加失败");
}
},function(err){
console.log(err);
});
this.value = "";
},
// 删除数据
del:function(id){
//点击删除按钮,从当前索引开始删除一个(相当于删除本身)
if(confirm('确定要删除这条数据吗?')){
//确定url
var url = "http://vue.studyit.io/api/delproduct/"+id
//获取数据
this.$http.get(url).then(function(res){
//提取数据
var data = res.body;
if(data.status == 0){
alert(data.message);
this.getData();
}else {
alert("数据删除失败");
}
})
}
},
},
//局部 自定义指令
directives:{
"focus":{
inserted:function(el){
el.focus();
}
}
},
//利用computed属性来进行逻辑计算
computed:{
//changeArr就是改变后的新数据数组
'changeArr':function(){
//内部获取不到this
var that = this;
//返回过滤出来的新数组
return this.arr.filter(function(ele,index){
//根据输入的字符查找对应索引的内容 !=-1就是可以查找到
return ele.name.indexOf(that.filterValue) != -1;
})
}
}
});
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。