目录
Vue中的侦听器(watch)
watch 概述
监测 Vue 实例变化的一个表达式或方法。回调函数得到的参数为新值和旧值,用一个函数取代。
简洁的说:watch 的作用可以监控一个值的变换,并调用因为变化需要执行的方法。可以通过watch 动态改变关联的状态。
普通监听
<!-- 普通监听 -->
<div id="app">
<input type="text" v-model="num">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: ''
},
watch: {
num(newVal, oldVal) {
// 监听 num 属性的数据变化
// 作用 : 只要 num 的值发生变化,这个方法就会被调用
// 第一个参数 : 新值
// 第二个参数 : 旧值, 之前的值
console.log('oldVal:', oldVal)
console.log('newVal:', newVal)
}
}
})
</script>
immediate(立即处理 进入页面就触发)
<!-- immediate(立即处理 进入页面就触发) -->
<div id="app">
<input type="text" v-model="num">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 1
},
watch: {
num: {
// 数据发生变化就会调用这个函数
handler(newVal, oldVal) {
console.log('oldVal:', oldVal)
console.log('newVal:', newVal)
},
// 立即处理 进入页面就触发
immediate: true
}
}
})
</script>
deep(深度监听)
对象和数组都是引用类型 ,引用类型变量存的是地址,地址没有变,所以不会触发 watch 。这时我们需要进行深度监听,就需要加上一个属性 deep,值为 true
<!-- 深度监听 -->
<div id="app">
<input type="button" value="更改名字" @click="change">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
food: {
id: 1,
name: '土豆'
}
},
methods: {
change() {
this.food.name = '西红柿'
}
},
watch: {
// 第一种方式:监听整个对象,每个属性值的变化都会执行 handler
// 注意:属性值发生变化后,handler 执行后获取的 newVal 值和 oldVal 值是一样的
food: {
// 每个属性值发生变化就会调用这个函数
handler(newVal, oldVal) {
console.log('oldVal:', oldVal)
console.log('newVal:', newVal)
},
// 立即处理 进入页面就触发
immediate: true,
// 深度监听 属性的变化
deep: true
},
// 第二种方式:监听对象的某个属性,被监听的属性值发生变化就会执行函数
// 函数执行后,获取的 newVal 值和 oldVal 值不一样
'food.name'(newVal, oldVal) {
console.log('oldVal:', oldVal) // 土豆
console.log('newVal:', newVal) // 西红柿
}
}
})
</script>
Watch 和 computed 的区别 :
Watch
watch 用于观察和监听页面上的 vue 实例,当你需要在数据变化响应时,执行异步操作,或高性能消耗的操作,那么 watch 为最佳选择
computed
可以关联多个实时计算的对象,当这些对象中的其中一个改变时都会触发这个属性
具有缓存能力,所以只有当数据再次改变时才会重新渲染,否则就会直接拿取缓存中的数据。
Vue中的过滤器(filter)
过滤器的写法
首先,过滤器可在 new Vue 实例前注册全局的,也可以在组件上写局部。
全局过滤器:
Vue.filter('globalFilter', function (value) {
return value + "!!!"
})
组件过滤器(局部):
上面有种写法有个需要注意的问题:全局注册时是 filter ,没有 s 的。而组件过滤器是 filters ,是有 s 的,这要注意了,虽然你写的时候没有 s 不报错,但是过滤器是没有效果的
过滤器的使用方法 :
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind
表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
Vue中的生命周期
一、vue 的生命周期是什么
vue 每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件 创建、数据初始化、挂载、更新、销毁 ,这就是一个组件所谓的 生命周期 。在组件中具体的方法有:
具体如下图:
二、vue 生命周期的在项目中的执行顺序
...
data() {
return {
rendered: false,
}
}
...
1. beforeCeate() {
console.log(this.rendered); // undefined
}
2. created() {
console.log(this.$el); //undefined
console.log(this.rendered); // false
}
3. beforeMount() {
console.log(this.$el); //undefined
}
4. mounted() {
console.log(this.$el);
}
5. beforeDestroy() {
console.log(this.$el);
console.log(this.rendered);
}
6. destroyed() {
console.log(this.$el);
console.log(this.rendered);
}
三、vue 中内置的方法 属性和 vue 生命周期的运行顺序 :
( methods、computed、data、watch、props )
props => methods => data => computed => watch
Vue中的网络请求
ajax、axios、fetch的区别
ajax
$.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function () {} });
传统 Ajax 指的是 XMLHttpRequest(XHR),最早出现的发送后端请求技术,隶属于原始 js 中,核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现回调地狱。
JQuery ajax 是对原生 XHR 的封装,除此以外还增添了对 JSONP 的支持。经过多年的更新维护,真的已经是非常的方便了,优点无需多言;如果是硬要举出几个缺点,那可能只有:
1.本身是针对 MVC 的编程, 不符合现在前端 MVVM 的浪潮 2.基于原生的 XHR 开发,XHR 本身的架构不清晰。 3.JQuery 整个项目太大,单纯使用 ajax 却要引入整个 JQuery 非常的不合理 (采取个性化打包的方案又不能享受 CDN 服务) 4.不符合关注分离( Separation of Concerns )的原则 5.配置和调用方式非常混乱,而且基于事件的异步模型不友好。
axios
// axios axios({ method: 'post', url: '/user/1234', data: { firstName: '张', lastName: '思瑞' } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
axios 是一个基于 Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生 XHR 的封装,只不过它是 Promise 的实现版本,符合最新的 ES 规范,它本身具有以下特征:
1. 从浏览器中创建 XMLHttpRequest 2. 支持 Promise API 3. 客户端支持防止 CSRF 4. 提供了一些并发请求的接口(重要,方便了很多的操作) 5. 从 node.js 创建 http 请求 6. 拦截请求和响应 7. 转换请求和响应数据 8. 取消请求 9. 自动转换 JSON 数据
fetch
// fetch fetch('http://example.com/movies.json') .then(function (response) { return response.json(); }) .then(function (myJson) { console.log(myJson); });
一、fetch 优势:
1. 语法简洁,更加语义化 2. 基于标准 Promise 实现,支持 async/await 3. 同构方便,使用 isomorphic-fetch 4. 更加底层,提供的 API 丰富(request, response) 5. 脱离了 XHR ,是 ES 规范里新的实现方式
二、fetch 存在问题 :
1. fetch 是一个低层次的 API ,你可以把它考虑成原生的 XHR , 所以使用起来并不是那么舒服,需要进行封装。 2. fetch 只对网络请求报错,对 400,500 都当做成功的请求, 服务器返回 400,500 错误码时并不会 reject, 只有网络错误这些导致请求不能完成时,fetch 才会被 reject。 3. fetch 默认不会带 cookie ,需要添加配置项: fetch(url, {credentials: 'include'}) 4. fetch 不支持 abort ,不支持超时控制,使用 setTimeout 及 Promise.reject 的 实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费 5. fetch 没有办法原生监测请求的进度,而 XHR 可以
axios 使用方法
1、基本用法
安装指令 => $ cnpm i axios --save
在 main.js
中引入 axios
import axios from 'axios'
Vue.prototype.$axios = axios
在组件中使用 axios
// 在组件中使用 axios
export default {
mounted() {
this.$axios.get('/goods.json').then(res => {
console.log(res.data);
})
}
}
2、axios 请求方法
axios可以请求的方法:
- get: 获取 数据,请求指定的信息,返回实体对象
- post:向指定资源 提交 数据( 例如表单提交或文件上传 )
- put:更新数据,从客户端向服务器传送的数据取代指定的文档的内容
- patch:更新数据,是对 put 方法的补充,用来对已知资源进行局部更新
- delete:请求服务器 删除 指定的数据
2.1、get 请求
示例代码 :
//方法一,请求格式类似于 http://localhost:8080/goods.json?id=1 this.$axios.get('/goods.json', { params: { id: 1 } }).then(res => { console.log(res.data); }, err => { console.log(err); }) //方法二 this.$axios({ method: 'get', url: '/goods.json', params: { id: 1 } }).then(res => { console.log(res.data); }, err => { console.log(err); })
2.2、post 请求
post 请求一般分为两种类型
- form-data 表单提交,图片上传、文件上传时用该类型比较多
- application / json 一般是用于 ajax 异步请求
示例代码 :
// 2.2、post 请求 //方法一 this.$axios.post('/url', { id: 1 }).then(res => { console.log(res.data); }, err => { console.log(err); }) //方法二 $axios({ method: 'post', url: '/url', data: { id: 1 } }).then(res => { console.log(res.data); }, err => { console.log(err); }) //form-data请求 let data = { //请求参数 } let formdata = new FormData(); for (let key in data) { formdata.append(key, data[key]); } this.$axios.post('/goods.json', formdata).then(res => { console.log(res.data); }, err => { console.log(err); })
2.3、put 和 patch 请求
示例代码 :
// put 请求 this.$axios.put('/url', { id: 1 }).then(res => { console.log(res.data); }) // patch 请求 this.$axios.patch('/url', { id: 1 }).then(res => { console.log(res.data); })
2.4、delete 请求
示例代码 :
// 2.4、delete 请求 // 参数以明文形式提交 this.$axios.delete('/url', { params: { id: 1 } }).then(res => { console.log(res.data); }) // 参数以封装对象的形式提交 this.$axios.delete('/url', { data: { id: 1 } }).then(res => { console.log(res.data); }) //方法二 axios({ method: 'delete', url: '/url', params: { id: 1 }, //以明文方式提交参数 data: { id: 1 } //以封装对象方式提交参数 }).then(res => { console.log(res.data); })
3、并发请求
并发请求:同时进行多个请求,并统一处理返回值
示例代码 :
// 3、并发请求 this.$axios.all([ this.$axios.get('/goods.json'), this.$axios.get('/classify.json') ]).then( this.$axios.spread((goodsRes, classifyRes) => { console.log(goodsRes.data); console.log(classifyRes.data); }) )
4、axios 实例
4.1、创建 axios 实例
示例代码 :
// 4.1、创建 axios 实例 let instance = this.$axios.create({ baseURL: 'http://localhost:9090', timeout: 2000 }) instance.get('/goods.json').then(res => { console.log(res.data); })
可以同时创建多个 axios 实例 。
axios 实例常用配置:
baseURL 请求的域名,基本地址,类型:String timeout 请求超时时长,单位ms,类型:Number url 请求路径, 类型:String method 请求方法, 类型:String headers 设置请求头,类型:Object params 请求参数,将参数拼接在URL上,类型:Object data 请求参数,将参数放到请求体中,类型:Object
4.2、axios 全局配置
示例代码 :
// 4.2、axios全局配置 // 配置全局的超时时长 this.$axios.defaults.timeout = 2000; // 配置全局的基本 URL this.$axios.defaults.baseURL = 'http://localhost:8080';
4.3、axios 实例配置
示例代码 :
// 4.3、axios实例配置 let instance = this.$axios.create(); instance.defaults.timeout = 3000;
4.4、axios 请求配置
示例代码 :
// 4.4、axios 请求配置 this.$axios.get('/goods.json', { timeout: 3000 }).then()
以上配置的优先级为:
请求配置 > 实例配置 > 全局配置
5、拦截器
拦截器:在请求或响应被处理前拦截它们
5.1、请求拦截器
示例代码 :
// 5.1、请求拦截器 this.$axios.interceptors.request.use( config => { // 发生请求前的处理 return config }, err => { // 请求错误处理 return Promise.reject(err); }) // 或者用 axios 实例创建拦截器 let instance = this.$axios.create(); instance.interceptors.request.use(config => { return config })
5.2、响应拦截器
示例代码 :
// 5.2、响应拦截器 this.$axios.interceptors.response.use( res => { // 请求成功对响应数据做处理 return res // 该返回对象会传到请求方法的响应对象中 }, err => { // 响应错误处理 return Promise.reject(err); })
5.3、取消拦截
示例代码 :
// 5.3、取消拦截 let instance = this.$axios.interceptors.request.use(config => { config.headers = { token: '' } return config }) // 取消请求拦截:this.$axios.interceptors.request.eject(instance); // 取消响应拦截:this.$axios.interceptors.response.eject(instance);
6、错误处理
示例代码 :
// 6、错误处理 this.$axios.get('/url').then(res = {}).catch( err => { //请求拦截器和响应拦截器抛出错误时,返回的 err 对象会传给当前函数的 err 对象 console.log(err); })
7、取消请求
主要用于取消正在进行的 http 请求 。
示例代码 :
// 7、取消请求 let source = this.$axios.CancelToken.source(); this.$axios.get('/goods.json', { // 只有配置 cancelToken: source 才可取消请求 cancelToken: source }) .then(res => { console.log(res) }) .catch(err => { // 取消请求后会执行该方法 console.log(err) }) //取消请求,参数可选,该参数信息会发送到请求的 catch 中 source.cancel('取消后的信息');
axios 封装代码(直接使用)
一、在组件中调用 封装在 http 文件中
import axios from 'axios' //创建 axios 实例 const axiosObj = axios.create({ baseURL: 'http://api.web1024.cn', timeout: 8000, params: { key: 'gxn759' } }) /** * 用于发送请求的通用方法 * @param {*} options 配置信息,method请求方法,params参数,path路由 * @returns */ async function http({ method = 'get', params, path }) { let result if (method === 'get' || method === 'delete') { await axiosObj[method](path, { params }).then(res => { result = res.data }, err => { result = err }) } else if (method === 'post' || method === 'put' || method === 'patch') { await axiosObj[method](path, params).then(res => { result = res.data }, err => { result = err }) } return result } export default http
二、需要挂载到
Vue
的时候 直接导入文件Vue.use(xxx)
就可以,Vuex
想用的时候, 直接导入以后直接使用就行index.js
import axios from "axios"; import Auth from '@/assrts/js/auth/js' import router from "@router/index.js"; // 基础配置 export const http = axios.create({ baseURL: "http://api.web1024.cn", timeout: 8000, params: { key: "gxn759", }, }); // 请求拦截器 http.interceptors.request.use( function (config) { if (config.url != "/login") { config.headers["Authorization"] = Auth.getToken(); } return config; }, function (err) { return Promise.reject(err); } ); // 响应拦截器 http.interceptors.response.use( function (response) { const { meta } = response.data; if (meta.status === 403) { window.alert("您没有权限执行该操作"); } else if (meta.status === 401) { window.alert("你的登录信息有误,请重新登录!"); router.push({ name: "login", query: { redirect: window.location.hash, }, }); } return response; }, function (err) { return Promise.reject(err); } ); //最后 const httpPlugin = {}; httpPlugin.install = function (Vue) { Vue.prototype.$http = http; };
Vue中的组件
组件(Component)是 Vue.js 最强大的功能之一。它可以扩展 HTML 元素,封装可重用的代码。
注册一个全局组件语法格式如下:
Vue.component(tagName, options)
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
<tagName></tagName>
全局组件
所有实例都能用全局组件。
<div id="app"> <runoob></runoob> </div> <script> // 注册 Vue.component('runoob', { template: '<h1>自定义组件!</h1>' }) // 创建根实例 new Vue({ el: '#app' }) </script>
局部组件
可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
<div id="app"> <runoob></runoob> </div> <script> var Child = { template: '<h1>自定义组件!</h1>' } // 创建根实例 new Vue({ el: '#app', components: { // <runoob> 将只在父模板可用 'runoob': Child } }) </script>
组件之间的数据传递
组件之间一般都是在总的大组件(vue实例)中请求拿到数据,再去传递到小组件,以此达到复用的目的。
Props(父→子)
Vue.component('my-component', { props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } })
自定义事件(子→父)
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口( Events interface ),即:
- 使用
$on(eventName)
监听事件- 使用
$emit(eventName)
触发事件另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
<div id="app"> <div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> </div> <script> Vue.component('button-counter', { template: '<button v-on:click="incrementHandler">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementHandler: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) </script>
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
其中,data 必须是一个 函数:
这样的好处就是每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例,如下所示:
<div id="components-demo3" class="demo"> <button-counter2></button-counter2> <button-counter2></button-counter2> <button-counter2></button-counter2> </div> <script> var buttonCounter2Data = { count: 0 } Vue.component('button-counter2', { /* data: function () { // data 选项是一个函数,组件不相互影响 return { count: 0 } }, */ data: function () { // data 选项是一个对象,会影响到其他实例 return buttonCounter2Data }, template: '<button v-on:click="count++">点击了 {{ count }} 次。</button>' }) new Vue({ el: '#components-demo3' }) </script>
自定义组件的 v-model
组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
<input v-model="parentData">
以下实例自定义组件 runoob-input,父组件的 num 的初始值是 100,更改子组件的值能实时更新父组件的 num:
<div id="app"> <runoob-input v-model="num"></runoob-input> <p>输入的数字为:{{num}}</p> </div> <script> Vue.component('runoob-input', { template: ` <p> <!-- 包含了名为 input 的事件 --> <input ref="input" :value="value" @input="$emit('input', $event.target.value)" > </p> `, props: ['value'], // 名为 value 的 prop }) new Vue({ el: '#app', data: { num: 100, } }) </script>
由于 v-model 默认传的是 value,不是 checked,所以对于复选框或者单选框的组件时,我们需要使用 model 选项,model 选项可以指定当前的事件类型和传入的 props。
<div id="app"> <base-checkbox v-model="lovingVue"></base-checkbox> <div v-show="lovingVue"> 如果选择框打勾我就会显示。 </div> </div> <script> // 注册 Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' // onchange 事件 }, props: { checked: Boolean }, template: ` <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > ` }) // 创建根实例 new Vue({ el: '#app', data: { lovingVue: true } }) </script>
实例中 lovingVue 的值会传给 checked 的 prop,同时当 <base-checkbox> 触发 change 事件时, lovingVue 的值也会更新。