mvvm是什么
- m 是vue实例中的data,自定义的数据或后端返回的数组不是后端mvc里的model概念不同。
- vm 是vue的实例 m和v之间的调度者 是mvvm的核心思想
- v是 html 要渲染的。
常用指令
- v-cloak 解决{{}}插值闪烁问题
- v-text 会先执行 覆盖 元素中原本的内容 但是插值表达式只会覆盖自己的占位符,默认不会闪烁
- v-html 渲染 html标签 覆盖元素中原有元素内容
- v-bind: 简写为: 用来绑定数据 可以写合法的js表达式
- v-on: 简写为 @ 用来点击事件
- v-if:DOM渲染与不渲染,不能和v-for一起使用
- v-for:循环渲染DOM,循环时要加v-key唯一标识,循环时不能和v-if一起使用,可以用computed计算属性再循环
- v-model:双向数据绑定,一般用于表单
- v-show:DOM隐藏与显示,和v-if区别在于v-show是利用css控制,实际上DOM已经渲染了,而v-if是渲染与不渲染。如果DOM频繁切换可以用v-show,反之用v-if。
常用事件修饰符
- stop 阻止冒泡 :外层和里层都有方法 点击里层会产生冒泡,也会触发外层的事件。顺序 从里到外产生事件
- prevent 阻止浏览器默认行为 :a标签有浏览器默认行为。
- capture 捕获事件 :点击里层先触发外层再触发里层 顺序从外到里产生事件
- self 只触发自己本身的事件 不会产生冒泡和捕获事件 类似于阻止冒泡 但只针对自己那一层 最外层还是会被最里层冒泡冒到 stop 是阻止所有层次
- once 事件只执行一次
数据的绑定
- v-bind: 数据的单向绑定
- v-modle :数据的双向绑定 这个只能用于表单元素中
class 绑定
1.数组带对象
<div :class="[classA,classB,{'classC':flag}]" >
data(){
return{
flag:true
}
}
tips:可以在类中的数组中写三元表达式,但推荐使用对象来代替它控制是否渲染
2.单纯的对象
<div :class="{classA:falg1,classB:flag2}" />
data(){
return{
falg1:true,
falg2:true
}
}
3.数组带三元
<div :class="['ac','bd',falg?'active','']" / >
data(){
return{
falg:true,
}
}
4.对象升级
<div :class="classObj" />
data(){
return{
classObj:{classA:falg1,classB:flag2}
}
}
5.使用style 的对象来实现样式的修改
<div :style="styleObj" />
data(){
return{
styleObj:{color:red}
}
}
6.使用style 的数组带对象来实现样式的修改
<div :style="[styleObj1,styleObj2]" />
data(){
return{
styleObj1:{color:red},
styleObj2:{color:red}
}
}
v-for的使用
- 可以遍历: 普通数组,对象数组,对象,还可以是数字
<div v-for='(item,key,index) in object' :key='index'>
{{item}}--{{key}}--{{index}}
</div>
<div v-for='(count in 10)'> </div>
v-if、v-show
- v-if 有较高的切换性能 , 适合元素可能永远不会被用户看到。
- v-show 有较高的初始渲染消耗,适合元素频繁切换。
生命周期 函数
- beforeCreate():这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它…
- created(): 这是遇到的第二个生命周期函数…
- beforeMount():这是遇到的第3个生命周期函数,表示 模板已经在内存中编辑完成,但是尚未把模板渲染(挂载)到页面中。在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串。就像{{text}}这样
- mounted():这是遇到的第四个生命周期函数,表示内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了。只要执行完这个生命周期,就表示整个vue实例已经初始化完毕了,此时,组件已经脱离了创建阶段,进入到了运行阶段。
- beforeUpdate():这时候表示,我们的界面还没有被更新[但数据已经被更新了页面中显示的数据,还是旧的,此时data数据是最新的。页面尚未和最新的数据保持同步
- update() : 这一步执行的是 先根据data中最新的数据,在内存中重新渲染出一份最新的内存dom树,当最新的内存dom树被更新后,会把最新的内存DOM树重新渲染到真实的页面中去,这时候,就完成了数据data(model层)->view(视图层)的更新,页面和data数据已经保持同步了,都是最新的。
- beforeDestory :当执行 beforeDestory 钩子函数的时候,Vue实例就已经从运行阶段,进入到销毁阶段, 当执行beforeDestroy的时候,实例身上所有的data和所有的methods以及过滤器、指令…都处于可用状态,此时,还没有真正执行销毁的过程。
- destroyed :当执行这个函数的时候,组件已经被完全销毁了,此时,组件中所有的数据,方法,指令,过滤器…都已经不可用了
父子组件通讯
1.父子组件传值,通过v-bind:(:)来传值,通过props来接收值
2.父组件用事件绑定机制传递方法给子组件—v-on 简写 @
3.emit 英文原意: 是触发,调用,发射的意思。
@handle=show 父组件传show方法给子组件。
子组件接收父组件的方法,并用$emit把子组件的值传给父组件
//父组件中
<component-name
:children='children' //传值
@handle='show' //绑定方法
>
</component-name>
data(){
return(){
children:11
}
}
methods:{
show(data){
}
}
//子组件中
methods:{
handle(){
this.$emit('func',{
age:1,
name:'搞事'
})
}
}
4.在父组件中接收子组件所有参数的同时,添加自定义参数
1.子组件传出单个参数时:
// 子组件
this.$emit('test',this.param)
// 父组件
@test='test($event,userDefined)'
2.子组件传出多个参数时:
// 子组件
this.$emit('test',this.param1,this.param2, this.param3)
// 父组件 arguments 是以数组的形式传入
@test='test(arguments,userDefined)'
子组件中的data数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如子组件通过ajax请求回来的数据,都可以放到data身上,data 上的数据都是可读可写的;
计算属性和监听器
计算属性 computed:
- 计算属性就是一些数据处理 放在computed中
- 直接当做普通属性调用不加括号
- 任何data中数据变化立即重新计算
<template>
<div>
<p>姓名:{{ name }}</p>
</div>
</template>
<script>
export default {
data() {
return {
fristname: "张",
lastname: "三",
};
},
computed: {
name() {
return this.fristname + lastname;
},
},
};
</script>
监听器 watch:
- 监听器 中的方法 为data中的变量名 ,括号中的返回值为变量名修改后的值
- 一般当一个值引起多个值改变的时候用监听器
- 多个值引起一个值改变时用computed
<template>
<div>
<p>单价:{{ armb }}</p>
<div>
<button @click="change(1)">-</button>
<p>数量:{{ age }}</p>
<button @click="change(2)">+</button>
</div>
<P>总价:{{ all }}</P>
</div>
</template>
<script>
export default {
data() {
return {
armb: 20,
age: 0,
all: 0,
};
},
methods: {
change(m) {
console.log(m);
if (m == 2) {
this.age++;
} else {
this.age--;
}
},
},
watch: {
age(age) {
this.all = this.armb * age;
},
},
};
</script>
slot 插槽
写插槽:
<div v-if="layout === 'block'" class="layout-block" :class="scroll?'layout-scroll':''">
<slot></slot> //匿名插槽
</div>
<!-- 左右块 -->
<div v-if="layout === 'both'" class="d-flex jc-between">
<div class="layout-both" :class="scrollLeft?'layout-scroll':''">
<slot name="left"></slot> //有名字的插槽
</div>
<div class="layout-both" :class="scrollRight?'layout-scroll':''">
<slot name="right"></slot>
</div>
</div>
使用插槽
//有名字的插槽 # v-slot的缩写是#
<template #left></template>
<template v-slot="left" > </template>
注意:区别对待v-slot="" 和v-slot:name; =和:的区别 一个是slot的name 一个是父组件获取子组件的数据,插槽一定要用template包裹着
Router 路由
先用命令行安装router npm install router vue-router --save
在index.js里面配置
//router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes=[
]
const router =new VueRouter({
routes,
mode:'history'//链接没有#的模式
})
export default router
// main.js
router import router from './router'
new Vue({
router //这里加入router
)
axios 网络请求
安装 axios npm install --save axios vue-axios
axios网络请求
1、安装
cnpm install axios -S
2、在main.js中引入
import Axios from 'axios'
3、在main.js中将Axios挂载到Vue的原型上(可选)
Vue.prototype.$axios=Axios
4、axios配置
axios({
baseURL:'', 路径前缀,会将url的路径添加到后面
url:'',
method: 'get', 不写默认是 get
timeout:n毫秒, 请求超时时间,若超过则取消
transformRequest: [function (data, headers) { 允许在向服务器发送前,修改请求数据,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
对data进行任意转换处理,必须返回一个字符串,或ArrayBuffer,或Stream
return data;
}],
transformResponse: [function (data) { 在传递给then/catch前,允许修改响应数据
return data;
}],
headers: {'X-Requested-With': 'XMLHttpRequest'}, 自定义请求头
params: { 会被添加到url中的请求参数
ID: 12345
},
paramsSerializer: function(params) { 参数序列化,如get请求传递的参数是个数组且报错,就可以使用这个选项将其序列化
不配置该参数,数组会默认转换为类似ids[]=1&ids[]=2&ids[]=3
return qs.stringify(params, {arrayFormat: 'brackets'}) 转换成类似ids[]=1&ids[]=2&ids[]=3
return qs.stringify(params, {indices: false) 转换成类似ids=1&ids=2&id=3
return qs.stringify(params, {arrayFormat: 'indices'}) 转换成类似ids[0]=1&aids1]=2&ids[2]=3
return qs.stringify(params, {arrayFormat: 'repeat'}) 转换成类似ids=1&ids=2&id=3
},
data:{作为请求主体被发送的数据,适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
键值对,会将请求体转换成json格式
},
data:'name=jeff&age=18', 会将请求体转换成url参数形式,即表单形式
withCredentials: false, 跨域请求时是否需要使用凭证
adapter: function (config) { 请求适配器设置,如前台发送ajax、nodejs中发送http请求
返回一个 promise 并应用一个有效的响应
},
auth: { 使用HTTP基础验证,并提供凭据这将设置一个`Authorization` 头,覆写掉现有的任意使用`headers`设置的自定义`Authorization`头
username: 'janedoe',
password: 's00pers3cret'
},
responseType: 'json', 服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseEncoding: 'utf8', 表示解码响应时使用的编码
服务器返回结果时会返回唯一的标识,下次发送请求得传递标识,检测成功才会相应,避免响应其他客户端发送的请求
xsrfCookieName: 'XSRF-TOKEN', 跨域请求cookie的标识
xsrfHeaderName: 'X-XSRF-TOKEN', 跨域头信息设置
onUploadProgress: function (progressEvent) { 上传处理进度事件
...
},
onDownloadProgress: function (progressEvent) { 下载处理进度事件
...
},
maxContentLength: 2000, 允许的响应内容的最大尺寸
maxRedirects: 5, 定义在node.js中follow的最大重定向数目
validateStatus: function (status) { 定义对于给定的HTTP响应状态码是resolve或reject promise,如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise将被resolve; 否则,promise将被rejecte
return status >= 200 && status < 300; // default
},
socketPath: null, 定义在node.js中使用的UNIX Socket的路径位置,如果使用了proxy代理,优先使用socketPath;
httpAgent: new http.Agent({ keepAlive: true }),`httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行http和https时使用的自定义代理,允许像这样配置选项:
httpsAgent: new https.Agent({ keepAlive: true }),
这将会设置一个`Proxy-Authorization`头,覆写掉已有的通过使用`header`设置的自定义 `Proxy-Authorization` 头。
proxy: { 'proxy' 定义代理服务器的主机名称和端口
host: '127.0.0.1',
port: 9000,
auth: { `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
username: 'mikeymike',
password: 'rapunz3l'
}
},
cancelToken: new CancelToken(function (cancel) {
取消axios请求的配置
})
})
4.5、axios全局配置:
全局axios配置:
所有的请求都会生效
axios.defaults.属性='xxxx'
自定义实例配置:
const instance = axios.create({
baseURL: 'https://api.example.com'
});
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
5、axios实例
可用于创建不同域名的请求
const instance=axios.create({
配置
})
使用: 使用方式和axios的两种方式相同
instance({url:'',...}).then((res)=>{...})
instance.get('url',{...}).then(res=>{...})
6、在组件函数中使用
(1)get请求:
axios.get("url",{配置})
.then(res=>{ res.data获取数据})
.catch(err=>{console.log(err)})//错误捕捉
(2)get请求传参:
方式一:在url后拼接参数
方式二:
axios.get('url',{params:{
键值对
}
}).then(res=>res.data)
.catch(err=>console.log(err))
axios({
method:'get',
url:'x',
params:{
键值对
}
}).then(res=>res.data)
(3)post请求
1、若被拦截,引入qs
import qs from 'qs' 将post的参数转换成url?键值对的形式,否则会被拦截
因为post中的键值对会以对象形式添加
2、创建请求
axios.post(url,data参数,{配置})
axios.post('url',qs.stringify({
键值对
}),{配置}).then(res=>{res.data}).catch(err=>console.log(err))
或
axios({
method:'post',
url:'x',
data:{...}或字符串格式
})
(4)当后台返回了状态码时
axios.get('url').then(
()=>{},
({response})=>{response.data} 获取错误情况下数据
)
(5)并行请求
方式一:
axios.all([axios请求1,axios请求2]).then((res)=>{
数组
res[0]/...
})
方式二:
axios.all([axios请求1,axios请求2]).then(
axios.spread((res1,res2)=>{
...
})
)
方式三:
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {...}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
(6)axios返回流式内容(前端axios无法使用,import引入的,后端axios才行)
(1)node_modules中找到axios
(2)将lib/adapters/http.js中的内容全选复制到lib/adapters/xhr.js
axios({method:'get',url,responseType:'stream'}).then(res=>{
res.data.pipe(fs.createWriteStream('C:/Users/10853/Desktop/'+title+".epub"))
})
案例:通过流读取下载电子书
axios({method:'get',url,responseType:'stream'}).then(res=>{
res.data.pipe(fs.createWriteStream('C:/Users/10853/Desktop/'+title+".epub"))
res.data.on('end',function(){
console.log('下载完毕');
})
})
(7)axios拦截器
拦截器中的两个方法参数和Promise的.then的方法参数效果相同
多个请求拦截器:后面的会先执行,因为两个方法参数是被unshift插入执行的集合中
多个响应拦截器:前面的会先执行,因为两个方法参数是被push进入执行的集合中
(1)添加请求拦截器
axios.interceptors.request.use(function (config) {
在发送请求之前做些什么,config为axios的配置对象
config.headers.Authorization=token
return config;
}, function (error) { 会接收请求拦截器中抛出的错误
对请求错误做些什么
return Promise.reject(error);
});
(2)添加响应拦截器
axios.interceptors.response.use(function (response) {
对响应数据做点什么,response为axios的返回结果对象
return response;
}, function (error) {
对响应错误做点什么
return Promise.reject(error);
});
(3)对某个实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
(4)删除拦截器
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
(8)取消请求
方式一:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
方式二:已废弃
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/rl', {
cancelToken: source.token 方式一:
cancelToken:new CancelToken((c)=>{
变量=c;
})
}).catch(err=>{
if (err.message == "interrupt") {
console.log('已中断请求');
return;
}
})
方式一中断请求:source.cancel('interrupt');
方式二中断请求:变量('interrupt');
(9)多个请求只发送一次,利用取消请求的特性
将取消请求的函数赋值给一个变量,当数据返回时将变量修改为null,每次请求判断变量是否为null,不是则取消
const CancelToken = axios.CancelToken;
let cont=null;
if(cont!==null){
cont();
}
axios.get('/rl', {
cancelToken: source.token 方式一:
cancelToken:new CancelToken((c)=>{
cont=c;
})
}).then(()=>{
cont=null;
})
import Vue from 'vue'
import App from './App'
import Axios from 'axios'
Vue.config.productionTip = false
Vue.prototype.$axios=Axios
/* eslint-disable no-new */
new Vue({
el: '#app',
data:{foo:'hello foo'},
components: { App },
template: '<App/>'
})
<template>
<div>
</div>
</template>
<script>
import qs from 'qs'
export default{
name:'d',
data()
{
return{
}
},
mounted()
{
this.$axios.get("http://localhost:3000/news")
.then(res=>{
console.log(res.data);
})
.catch(err=>{
console.log(err)
})
this.$axios.post("http://localhost:3000/movie",qs.stringify({id:2})).then(res=>console.log(res.data)).catch(err=>console.log(err))
}
}
</script>
<style lang="css">
</style>