CLI:Command-Line Interface 命令行界面(俗称脚手架)
在runtime-complier中的过程是这样的:
template->ast->render函数->虚拟dom->真实dom(UI)
在runtime-only中的过程是这样的:
render函数->虚拟dom->真实dom(UI)
代码的区别:runtime-complier:
runtime-only:
开发时(npm run dev)
其中App对象中的template会被vue-template-compiler编译成render
路由就是通过互联的网络把信息从源地址传输到目的地址的活动。
路由提供了两种机制:路由和转发
路由表(映射表):地址到电脑的对应关系
后端渲染:页面是在后端渲染完,
后端路由:后端(服务器)处理URL和页面之间映射关系。
前端渲染:
前后端分离:一个url对应一个html+css+js,有多个映射
单页面富应用阶段 SPA simple page application
前端路由管理url和页面(从js分离出来的将要渲染的组件)直接的映射关系,
只从服务器请求一套html+css+js,改变url页面不进行刷新(不再向服务器重新请求资源)
修改url且不发生刷新:
location.hash=‘xxx’
history.pushState({},’’,‘home’)
要修改的一些文件:
index.js主要用于配置路由信息,包括配置url和组件的映射信息等,设置默认路径,path为空时重定位到指定的路由
//配置路由信息
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../components/Home.vue'
import About from '../components/About.vue'
import User from '../components/User.vue'
//通过Vue.use(插件),安装插件
Vue.use(Router)
//创建Router对象并导出
export default new Router({
mode: 'history',//不要hash模式
linkActiveClass: 'active',//把router-link-active名字改一下
//配置路由和组件之间的映射关系
routes: [
{
//设置一个默认路径
path: '',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
},
{
path: '/user/:userID',
component: User
},
]
})
App.vue:
router-link to这样点击了它就跳转到相关路由(包括代码修改的方式$router方式),一些属性tag、replace(就不能前进后退了)、router-link-active(哪个路由是活跃的,它的tag会被添加这个class,可以在index.js更改名称);
动态路由的使用,在index.js里定义了:userID它会动态显示,具体代码见下面
<template>
<div id="app">
<h2>i am APP</h2>
<!-- <router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button" replace>关于</router-link> -->
<!-- <button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button> -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<!-- 注意不变的字符串要加单引号 -->
<router-link v-bind:to="'/user/'+userID">用户</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
methods: {
//通过代码的方法修改路由
homeClick() {
//this.$router拿到的就是index.js里面new Router的实例化对象
// this.$router.push("/home");
this.$router.replace("/home");
},
aboutClick() {
// this.$router.push("/about");
this.$router.replace("/about");
}
},
data() {
return {
userID: "LiSi" //这里记住要是字符串啊
};
}
};
</script>
<style>
.active {
color: red;
}
</style>
User.js:通过$route.params可以获得活跃路由的属性,userID指的就是index.js里面path写的:userID,即App.vue里面data(){}里定义的userID值(我们把path改为 path: ‘/user/:abc’, 则 $route.params.abc就是userID
<!-- -->
<template>
<div>
<h2>i am user</h2>
<p>我的用户{{userID}}</p>
<p>{{$route.params.userID}}</p>
</div>
</template>
<script>
export default {
data() {
return {};
},
//生命周期 - 创建完成(访问当前this实例)
created() {},
//生命周期 - 挂载完成(访问DOM元素)
mounted() {},
computed: {
userID() {
// this.$route拿到的是谁处于活跃就拿到的谁,params后面的属性就是index.js里面 path: '/user/:userID', ':'后面跟的啥就是什么
return this.$route.params.userID;
}
}
};
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>
npm run build后:
app是业务代码
main对打包的模块化代码做底层支撑
vendor是插件(扩展工具如vue vue-loader的打包)
1.在components文件夹下新建Home下的组件:内容自定义
2.在index.js里配置路由映射关系:
3.在HOME.vue里添加组件:
第一种方法见前面的代码:
使用方法就是在对应的组件里用$route.params.xxx
第二种方法:
index.js里面定义常规的:
在App.vue里面:把to后面写成对象的形式,query代表查询(见url的组成)
得到的url:
在profile.vue里面使用时:
如果要换成点击button通过methods来更换url的话:
$router在每个地方拿到都是一样的:
$route拿到的是是当前活跃的路由:
vue的所有组件都继承自vue的原型。
当我们需要把document.title也随着我们点击component而改变时,可以:
方法1:直接在每个component的生命周期函数里添加:(缺点是每个都添加很麻烦)
方法2:在index.js里,路由里添加meta和title,下面调用router.beforeEach()注意它的参数,以及一定要再调用next()这个函数,原始代码:to.meta.title在有路由嵌套的地方不能正常显示所以要改为:
发生在beforeEach和afterEach中间
其他:组件内的导航守卫
关于生命周期(要记住图):每次我们不再使用当前组件时,组件会被销毁,如果我们希望组件保留可以写成:
则activated和deactivated奏效:
当首页有多个路由时怎么才能保持:
1.取消路由的默认重定向,在home这里重定向:
2.给home添加如下代码:
正则匹配的参数是每个组件的name,
注意正则的写法:
Promise是异步编程的一种解决方案,链式编程。
当我们有多个异步操作嵌套的时候(一般发生在网络请求里,请求的数据又继续请求数据)会产生回调地狱:这里遇到resolve()时会执行then里的函数,并且把resolve里的参数传给then。下面的代码显示多行hello world.
处理失败时调用reject再执行catch里的函数。
promise的三种状态:async指的异步,sync同步
另外的处理形式:
可以在then里面写两个函数,第一个表示满足时的,第二个表示拒绝时的:
最基础的写法:
<script>
new Promise((resolve, rejected) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一次处理');
return new Promise((resolve) => {
resolve(res + '111')
})
}).then(res => {
console.log(res, '第二次处理');
return new Promise((resolve) => {
resolve(res + '222')
})
}).then((res) => {
console.log(res, '第三次处理');
})
也可以把return new Promise(()=>{})简写成:
return Promise.resolve()
new Promise((resolve, rejected) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一次处理');
return Promise.resolve(res + '111')
}).then(res => {
console.log(res, '第二次处理');
return Promise.resolve(res + '222')
}).then((res) => {
console.log(res, '第三次处理');
})
还可以这样简写它会自己用Promise.resolve封装:
new Promise((resolve, rejected) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一次处理');
return res + '111'
}).then(res => {
console.log(res, '第二次处理');
return res + '222'
}).then((res) => {
console.log(res, '第三次处理');
})
当其中有一个是rejected:下面的代码会打印:
aaa,第一层的10行处理代码
error message
也可以手动抛出异常 throw ‘xxx’,然后把xxx传给catch的参数并打印
某一个需求需要发送多次请求才能完成的话:promise里面的参数是可迭代对象(数组),当两个请求都满足后再执行then,这时候results是数组。
<script>
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result1');
}, 1000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result2');
}, 2000)
})
]).then(results => {
console.log(results);
})
</script>
构建一个tabbar方便以后使用:
注意下面的tabbar里是插槽slot(放了多个tabBarItem)
每个tabBarItem也有三个slot存放图片和文字
注意一个props传值:
在之前学的props用来父传子值,这里我们点击tabBarItem需要给this.$router现在的path,那么可以在父组件APP.vue里的tabBarItem增加path属性。
具体见代码(这里就不放了可以看coderwhy老师的)
补充一下async/await
asycn函数返回的是一个promise对象,await相当于暂停一下,执行teat2(),返回promise对象,对象状态是fuliled,值是undefined,然后awiat test2()相当于promise.then() ,result拿到这个undefined(这里可以看着是reslove()括号里的参数给了result)后面的语句异步执行的。
await后面一般跟promise对象,async函数(因为他也会返回一个promise对象),一个参数(会被自动包装成promise对象)
(执行步骤见代码上的编号哦)
再来个例子:
如用户点击页面按钮counter++
首先安装vuex (npm install vuex --save)
创建store文件夹和index.js文件:
在main.js里挂载vuex
要在组件里用store里的counter:
$store.state.counter
注意当我们想修改state里的状态值时:
Devtools会记录我们修改的state,但它只能记录同步的信息,异步操作时记录的信息会出错。
actions是当我们有异步操作时(这里有后端请求API),要在里面做,因为mutation只能做同步操作。
当我们想要修改state的值,在mutation里定义方法:
在组件里:
(类似于计算属性那种,要对state里的东西进行变化,且常常获取)
默认的参数是state和getters
如我们需要counter是平方:
在组件里:
注意我们的getters里定义的方法还可以获取同样在getters里方法的东西:
当我们想要从组件里传入一个参数到getters里的方法里时,我们就在getters里面返回函数就可以传参。
如
但是回调函数还可以带别的参数payload 意为负载,可以是对象、number…,当参数不止一个需要是对象(见下面)
如下:increment称为事件类型,后面跟的(){}为回调函数
案例:我们需要点击时加不同的数字,需要提交commit时传入这个参数:
在APP.vue里:
这样不会添加到响应式系统,意思是Info确实增加了,但界面不会发生刷新:
用push、pop方法是可以的,是响应式的
可以用Vue.set方法,如下:相当于给info增加address属性,值为洛杉矶
注意要删除的话:
注意我们可以给type都写进mutations-types.js文件里:如
然后在要用到该type的地方导入,并且用统一的写法就不会出现拼写错误
APP.vue
当我们的操作是异步的时候,不能直接在mutations里面写,需要在actions里面写:
如:当我们用setTimeout时
对应的context和payload在APP.vue:
context也有commit方法,所以执行的还是mutations里定义的:
此外还建议用promise的方法来写:
相当于把下面的this.$store.dispatch()替换成了new Promise() 遇到reslove后就传递给then
它默认的就是在state里定义了modules里的内容(a,b)
定义如下:
在const store里:
在APP.vue里要使用:
另外写在module里的actions,它的context参数是一些对象:state,commit,rootState…
对象的解构方法可以在这用:
注意vuex要模块化开发(具体见 https://www.bilibili.com/video/BV15741177Eh?p=141&spm_id_from=pageDriver)
默认的是get请求,params和get请求对应,会把params写在url的问号后面,post请求传data,它是写在body里的(好像也可以传params)
也可以创建多个实例.
网络封装,不然后期维护成本大:
封装的方法:
request.js
axios return的本来就是一个promise,就可以不用new promise
请求的时候:
全局:
实例:
当发送请求是成功的,就打印config,失败的话才会来到err
此外要把拦截的config给return回去不然request就失败了
不然就会打印request的err
响应拦截: