1.Vue是什么?
1.1 vue就是一个js文件:vue.js
2.2 官网链接:https://cn.vuejs.org/ ,官网vue是什么:渐进式javascript框架
2.3为什么设计成一个渐进式框架
vue.js是一个核心库(毛坯房)
如果需要添加额外的插件(安装下载):都是依赖于vue.js
2.Vue.config.js配置文件信息
配置参考:https://v2.cn.vuejs.org/zh/config
1.README.md:说明文件
2.package.json :模块依赖和很多配置
3.node_modules:下载模块
4.src目录: main.js:全局文件 App.vue:第一个入口文件
5.assets:放入静态资源
6.components:放入组件
6.public目录 index.html===>运行localhost:8080访问的页面==》项目的html
3.v-if和v-show的区别(面试题)
v-if和v-show都是控制显示和隐藏。
3.1v-if和v-show如果都是false的情况
v-show是隐藏(v-show是显示和隐藏盒子)。
v-if是删除(v-if是创建和删除盒子)。
3.2.首次加载页面==》开销问题
v-show ==>就算设置了false,这个盒子也是存在的。
v-if ==>他是不存在的,当我设置为true时才创建盒子出来。
3.3.频繁的切换
v-show 显示和隐藏。
v-if 创建和删除,不断的创建和不断的删除,开销要大。
4.vue中的数据流
4.1我们在data中return中定义的数据,本身应该是this.$data.xxx可以拿到,但是this.xxx也可以拿到,就证明vue源码中 做了这样的操作:把data的所有数据赋值给了当前大对象
4.2methods定义的方法,也要赋值给大对象 在控制台打印($this)得到大对象
5.vue中计算属性
5.1 了解什么是计算属性(computed)
针对于数据进行第二次计算(强调其实template部分也可以实现,但是最好把二次计算写在computed,因为直接写在template会让template代码很难维护和管理),computed跟methods同级。
5.2二次计算的情况,methods也可以实现,那么methods和computed有什么区别?
最大区别:computed有缓存
5.3computed的写法
普通写法
computed:{
total(){
return this.price*this.num
}
}
以上的普通的写法,值是不可以直接修改的this.total=‘123’
get和set写法
change:{
get(){ return this.str};
set(val) {this.str=val}
}
6.属性绑定的写法(单项数据流:M==>V)
6.1单项数据流(v-bind)
M(JS的数据) ===》V(视图:template)去使用
注意:如果是单项数据流,视图修改了值,M的值不变(不会更新)
6.2写法(简写)
<input type='text' v-bind:value='str'/>
<input type='text' :value='str'/>
v-bind:value==>:value
v-bind:src===>:src
v-bind:class===>:class
7.Vue的开发模式:MVVM
v-bind:xxx ==>单向绑定(单向数据流)
v-model ==>双向绑定(双向数据流)
7.1在vue中如何实现单向绑定(面试题)
v-bind
7.2单向绑定和双向绑定的使用场景
7.2.1单向绑定:纯展示
7.2.2双向绑定:有修改或输入行为:在页面输入的内容,在js部分还要获取
8.设置跨越
8.1 vue.config.js配置:https://cli.vuejs.org/zh/config
8.2如果前端应用和后端API服务器没有运行在同一台主机上,你需要在“在开发环境”下将API请求代理到API服务器。这个问题可以通过vue.config.js中的devServer.proxy选项来配置
注意:设置代理在开发环境下生效,生产环境不生效
8.3 在vue.config.js中配置代理来解决跨域的问题(配置完代理一定要重启服务器)
devServe:{
proxy:'http://localhost:30000'
}
8.4 开发阶段和生成阶段
开发阶段:写代码的时候(项目还没有上线)
生产阶段:代码写完了(项目要上线了)
8.5 vue 项目开发完成后,打包操作
npm run build
8.6 vue的环境变量
为了解决开发阶段和生产阶段的代理问题而引进来的
8.6.1 创建环境变量文件
在vue项目根目录下创建:
.env.development ===>开发环境(文件中的内容是:VUE_APP_BASE_URL=http://localhost:3000)
.env.production==>生产环境(文件中的内容是:VUE_APP_BASE_URL=99http://localhost:3000)
8.6.2 .env文件中属性名必须以VUE_APP_开头
***调用要重启vue项目
8.6.3 调用.env文件中的变量
process.env.VUE_APP_XXX
在axios设置基本路径哪写一个三目运算符
总结:请求接口:会有2种情况:
1.前端不用处理跨域:不需要设置代理解决跨域问题
2.前端需要处理跨域问题 :设置代理,设置环境变量
9.axios
9.1在vue项目中,一般使用: axios,fetch来发起请求,将数据渲染到页面上。
官方参考网址:http://www.axios-http.cn
9.2在项目中如何使用axios
安装axios:cnpm i axios -S, 在created中发送请求
-S 是安装在dependencies跟随项目安装在服务器
-D 是安装在devDependencies
9.3 基础用法
1.get请求
axios.get('url?act=1&id=2')
2.post请求
axios.post('url',{
act:1,
id:2
})
3.配置写法
let res=await axios({
url:'',
methods:'post',//默认是get请求
headers:{},//自定义请求头
data:{},//post请求,前端给后端传递的参数
params:{},//get请求,前端给后端传递的参数
timeout:0,//请求超时
responseType:'json',//返回数据类型
})
9.4 axios的二次封装
在项目中统一对axios封装的文件放在utils文件下,在main.js引入
import axios from 'axios'
const TimeOut = 3600 // 定义超时时间
// 创建一个axios的实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // 设置axios请求的基础的基础地址
timeout: 5000 // 定义5秒超时
})
// 请求拦截器
service.interceptors.request.use(config=>{
// 在这个位置需要统一的去注入token
config.headers['Authorization']=`Bearer ${store.getters.token}`
}
return config // 必须返回配置
},err=>{
return Promise.reject(error)
})
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
export default service // 导出axios实例
9.5 api的解耦 @代表src目录说
9.5.1 api解耦的意义
1.为了同一个接口可能多次使用,那么封装起来直接调用就可以
2.为了方便api请求的统一管理(在view目录下新建api文件夹,里面放每个模块的请求接口)
总结:
不管什么情况,vue项目:axios二次封装和api解耦是一定会做的
10.vue生命周期
- beforeCreate(创建前)
- created (创建后)
- beforeMount (载入前)
- mounted (载入后)
- beforeUpdate (更新前)
- updated (更新后)
- beforeDestroy( 销毁前)
- destroyed (销毁后)
面试题1:第一次进入页面(组件)会执行那些生命周期函数
beforeCreated,created,beforeMount,Mount
面试题2:在那个阶段有data或el
beforeCreate(创建前):没有data,没有el
created (创建后):有data,没有el
beforeMount (载入前):有data,没有el(不过在准备了)
mounted (载入后):有data,有el
data:获取当前组件的data数据,el:获取当前组件的dom
面试题3:用过那些生命周期函数,在什么情况下用?
created:请求接口,mounted:获取dom
11.$nextTick
获取更新后的dom(onload完成后获取)
想要获取更新后的dom:this.nextTick,在beforeCreated,created,beforeMount想要获取dom,可以使用nextTick
$nextTick原理:
是一个异步操作,返回一个promise
class Vue{
constructor(optios){
this.$data=options.data;
optios.created.bind(this)();
this.$el=document.querySelector(options.el);
options.mounted.bind(this)();
}
$nextTick(callback){
return Promise.resolve().then(()=>{
callback()
})
}
}
//调用:
mounted(){
console.log(this.$nextTick(()=>{
console.log(this.box.height)
}))
}
ref:获取bom
<div ref='box'></div>
this.$refs.box
12.vue组件
12.1创建组件(就是一个.vue文件)
组件管理:统一放到src/components里面
组件命名:首字母要大写
12.2 引入组件
import 组件名字 from 组件路径
<组件名字/>
13.路由有几种模式,有什么区别
有两种模式:hash,history
1.关于找不到路由的情况:history:会发送一个get请求,hash:不会额外发送一次get请求
2.展示形式不一样:hash:带了一个#
14.routerlink和routerView的区别
router-view: (会显示某一个组件)
相当于 路由网址匹配到的组件 会渲染到当前组件的这个标签上
当地址栏的网址改变时,如果新网址跟提前注册路由匹配,就会加载注册的组件
遇到这个 标签,就会去匹配路由
1、router-link:相当于a标签,给我们提供跳转到某个路由的功能,如果没有匹配到路由就会跳转失败:
<router-link to="/login"> xx<router-link >
<router-link to="{path:'/login'}"> xx<router-link >
2、编程式跳转(JS跳转-编程式导航):
this.$router.push("/login")
this.$router.push({path:"/login"}
this.$router绑定在组件原型链上的,路由对象,它有一些功能
15.VueRouter, router, route区别
VueRouter是一个nodejs识别的模块包
route是路由匹配时,携带了一些信息的对象,包括path,params,hash,query等等信息
router是路由实例对象,包含了路由的跳转方法,钩子函数等等
16.路由守卫guard/导航钩子
16.1全局守卫:beforEach,afterEach
to:将要去那个页面,from:从哪个页面,next()放行
//全局前置守卫
router.beforeEach((to, from, next) => {
//用户未登录只能访问首页、登录注册页面
if (to.path == "/" || to.path == "/login" || to.path == "/register") {
next();
} else {
//去其他页面判断是否登录
let flag = window.localStorage.getItem("email");
//登录过直接放行
if (flag) {
next()
} else {
//未登录则跳转到首页
Message({
message: '您尚未登录哦,请先登录!',
type: 'warning',
duration: 1500
});
next("/");
}
}
})
//全局后置守卫
router.afterEach((to, from) => {
window.scrollTo(0,0)
})
16.2路由独享的守卫(beforeEnter(to,from,next))
写在router下的index.js里面的path,name、component的后面
routes:[{
path:"/test",
component:()=>import("../components/Test.vue"),
beforeEnter(to,from,next){
if(to.path==="/test"){
alert("请登录");
next(false); // 禁止跳转
}else{
next()
}
}
}]
16.3组件内部生命周期守卫(*beforeRouteLeave,beforeRouteEnter,beforeRouteUpdate)
beforeRouteLeave,beforeRouteEnter,beforeRouteUpdate
动态添加路由:addRoute
17.vuex
状态管理模式,通俗讲集中式存储管理
存储的东西有:全局共享属性,全局共享方法
17.1 vuex的使用场景
很多组件共用一个值的时候,数据统一管理
17.2 vuex的属性
state:存放数据的仓库
使用一:this.$store.state.xx
使用二:使用辅助函数
<script type="text/javascript">
import {mapState} from 'vuex'
export default{
computed:{
...mapState(['str1'])
}
}
</script>
//调用
{{str1}} 或 this.str1
以上两种区别:
方式一:其实是在store本身里面找到的属性值,从数据源取出来的,可以修改属性值
方式二:辅助函数的形式==》mapState会把state的某一值拷贝一份给vue当前的组件的对象,不可以直接修改
getters:类似于组件的computed属性
使用一:this.$state.getters.xxx
使用二:辅助函数
因为vuex是单线数据流,所以v-model绑定getters会报错,而且没有get和set的写法
mutations:唯一修改state中数据
使用一:辅助函数
<script type="text/javascript">
import {mapMutatios} from 'vuex'
export default{
methods:{
...mapMutations(['add'])
}
}
</script>
//调用
<button @click='add(10)'></button>
使用二:通过commit方式提交mutations
this.$store.commit(‘add’,20) 是store来提交mutations
actions:存放异步方法
使用一:actions:{total({commit,state}){state.num++}}
使用二:this.$store.dispatch(‘taotal’,20)
方法总结:mutations可以通过commit来提交,actions可以通过dispatch来提交
modules:模块,方便管理
18.vuex持久化存储
当某一个组件使用了vuex的数据,比如把1修改成了2,刷新页面又到了1该怎么办?【Vuex的持久化存储】
- 自己写localStorage
- 使用插件 https://www.xuexiluxian.cn/blog/detail/beebe5210b54417cb061f9e8b515bb
1.安装 npm i vuex-persistedstate
2. import createPersistedState from “vuex-persistedstate”;
export default new Vuex.Store({
modules: {
shop,
user
},
3. plugins:[
createPersistedState({
// 存储的 key 的key值
key: “xiaoluxian_store”,
})
]
})
18.1 面试题:在某个组件中可以直接修改vuex的状态(数据)吗?
可以的:1.通过mutations方法来修改
2.组件直接修改vuex数据源 ==》this.$store>state.shop.num=200
不可以:1.直接使用辅助函数
this.num ==>这种情况时不可以修改的
19.插槽
19.1 匿名插槽
插槽没有名字
父:
<HelloWorld>
<div>11111</div>
</HelloWorld>
子:
<slot></slot>
<input type="" name="">
19.2具名插槽
插槽有名字,可以对应放到某一个位置上
父:
<HelloWorld>
<template #header>
<div>11111</div>
</template>
<template #footer>
<div>22222</div>
</template>
</HelloWorld>
子:
<slot name='header'></slot>
<input type="" name="">
<slot name='footer'></slot>
19.3作用域插槽(传值)
子组件提供给父组件的参数,该参数仅限于插槽中使用,父组件可根据子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容。
父组件
<template>
<div class="child">
<h3>这里是子组件</h3>
<slot :data="data"></slot>
</div>
</template>
export default {
data: function(){
return {
data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
}
}
}
子组件:父组件通过 “slot-scope” 来接收子组件传过来的插槽数据,再根据插槽数据来填充插槽的内容
<template slot-scope="user">
<div>
<span v-for="item in user.data">{{item}}</span>
</div>
</template>
20.查找父子组件(this.parent,this.children)
20.1 查找父组件
this.$parent ==>返回当前组件的父组件实例
this.$root > 根组件(如果当前实例没有父实例,此实例将会是其自己)>app
20.2查找子组件
this.$children==>当前组件的所有子组件的列表(中返回的是子组件的实例)
this.$children[0].xxx=‘aaa’ ==>可以直接修改子组件的值
20.3 面试题:父组件想要直接获取修改子组件的数据怎么办?
1.this.$children[0].xxx=‘aa’
2.在父组件引入子组件中,在子组件上加入ref
获取子组件:this.refs.img
修改子组件的数据:this.refs.img.xxx=‘aaa’
21.$set是干什么的,使用场景
使用场景:当修改一个响应式数据的时候,数据本身改变了但是视图没有进行更新使用$set来更新
语法:
this.$set( 目标 , 修改的key或下标 , 修改后的值 );
let arr = ["星期一","星期二","星期日"]
this.$set(arr,2,"星期三") //第一个参数是数组,第二个参数是下标索引,第三个参数是新的内容
//更新之后的arr是["星期一","星期二","星期三"]
//对象的属性sex的值更新为"男"
let obj = {name:"六四",age:18,sex:"女"}
this.$set(obj,"sex","男") //第一个参数是对象,第二个参数是更新的属性名称,第三个参数是新的内容
//更新之后的obj是 {name:"六四",age:18,sex:"男"}
22.依赖注入(provide/inject)
某组件可以直接让它下面的组件传值(没有组件的父子限制)
场景:顶层组件给后代组件传值
缺点:不知道数据来源
用法:
父组件:
provide(){
return { num:this.user}
}
子组件:
inject:["user"]
{{user}}
23.混入(mixins)和vuex的区别
混入功能:有点像工具类,所以是全局的,可以导出全局属性和方法
vuex:状态管理==》state数据,数据是共享的
属性区别:混入的属性他们不相互影响,vuex中的属性是共享的
方法的区别:混入的方法是可以return,vuex没有return