Vue2.0项目入门笔记(1)23.5.18
1、创建项目
vue-cli脚手架初始化项目
node+webpack+淘宝镜像
node_modules文件夹:项目依赖
1)public文件夹:一般放一些静态资源,注意:放在public文件夹中的静态资源,webpack进行打包的时候,会原封不动的打包到dist文件夹中。
2)src文件夹(程序员源代码文件夹):
assets文件夹:一般也是放静态资源(一般是放置多个组件共用的静态资源),注意:放置在assets文件夹里面静态资源,在webpack打包的时候,webpack会把静态资源当做一个模块,打包JS文件里面。
components文件夹:一般放置非路由组件(全局组件)
App.vue:唯一的根组件,Vue当中的组件
main.js:程序入口文件,也是整个程序中最先执行的文件
3)babel.config.js:配置文件(babel相关)
4)package.json文件:认为是项目的身份证,记录项目叫做什么,有哪些依赖,项目怎么运行
5)package-lock.json:缓存性文件
6)ReadME.md:说明性文件
2、配置
2.1项目运行,浏览器自动打开
package.json

2.2 eslint校验功能关闭
在根目录下,创建一个vue.config.js文件
2.3 src文件夹简写方法,配置别名
@代表的是src文件夹。
2.4项目路由分析
注意1:创建组件的时候,组件结构+组件样式+图片资源
注意2:项目如果采用less样式,需要通过less、less-loader进行处理,把less样式变为css样式,浏览器才可以识别。
安装依赖:npm install --save less less-loader@5
注意版本号!
注意3:style标签样式更改
<style lang="less" scoped>
2.4.1使用组件的步骤(非路由组件)
-
创建或者定义
-
引入
-
注册
-
使用
2.4.2路由组件的搭建
npm install --save vue-router
路由组件一般放置在pages/views文件夹里面。
1、配置路由
项目当中配置的路由一般放置在router文件夹中
引入路由->使用插件->引入路由组件->配置路由(对外暴露)
//配置路由
import Vue from "vue";
import VueRouter from "vue-router";
//使用插件
Vue.use(VueRouter);
// //引入路由组件
import Home from '@/pages/Home'
import Search from '@/pages/Search'
import Login from '@/pages/Login'
import Register from '@/pages/Register'
//配置路由
export default new VueRouter({
routes:[
{//重定向 在项目跑起来的时候 访问/,立马让他定向到首页
path:'*',
redirect:"/Home",
meta:{show:true}
},
{
path:"/Home",
component:Home,
meta:{show:true}
},
{
path:"/Search/:keyword",
name:Search,
component:Search,
meta:{show:true}
},
{
path:"/Login",
component:Login,
meta:{show:false}
},
{
path:"/Register",
component:Register,
meta:{show:false}
}
]
})
千万不要忘记:再在main.js入口文件中引入并注册!
最后在组件中用router-view标签显示路由:
在main.js里面注册完路由,组件身上都拥有$route,$router属性,
$route和$router区别:
$route:一般获取路由信息【路径、query、params等等】
$router:一般进行编程式导航进行路由跳转【push|replace】
重定向:
在项目跑起来的时候,访问/,立马让他定向到首页
路由的跳转:
路由的跳转有两种形式:
1.声明式导航router-link,可以进行路由跳转,务必要有to属性
<router-link to="/login">登录</router-link>
<router-link to="/register" class="register">注册</router-link>
2.编程式导航push|replace,可以进行路由跳转
<button class="sui-btn btn-xlarge btn-danger" type="button" @click="goSearch">
搜索
</button>
methods:{
//搜索按钮的回调函数:需要向search路由进行跳转
goSearch(){
//路由传递参数
//第一种:字符串形式
//params参数 {{$route.params.keyword}} query参数 {{$route.query.k}}
//this.$router.push("/search/"+this.keyword+"?k="+this.keyword.toUpperCase());
//第二种:模板字符串
//this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`);
//第三种:对象 需要给路由取别名name
//this.$router.push({name:"Search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}});
let locations = {
name: "search",
params: { keyword: this.keyword || undefined },
};
//确定路径当中有query参数
if (this.$route.query.categoryName) {
locations.query = this.$route.query;
}
this.$router.push(locations);
}
}
编程式导航:声明式导航能做的,编程式导航都能做,但是编程式导航除了可以进行路由跳转,还可以做一些其他的业务逻辑
组件显示与隐藏:
v-if和v-show:显示或者隐藏组件使用v-show更好,
(1).手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐;
(2).编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;
(3).编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;
只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载);
v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
(4).性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
(5).使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。
什么时候使用v-if,什么时候使用v-show?
当组件中某块内容只会显示或隐藏不会被再次改变显示状态,此时用v-if更加合适,例如请求后台接口通过后台数据控制某块内容是否显示或隐藏,且这个数据在当前页不会被修改;
当组件某块内容显示隐藏是可变化的(元素频繁显示和隐藏),此时用v-show更加合理,例如页面中有一个toggle按钮,点击按钮来控制某块区域的显示隐藏。
原因:
频繁操作dom对性能影响很大,v-if如果用在有toggle按钮控制的情况下,相当于在频繁增加dom和删除dom,
所以此时用v-show更加合适,如果只是要么显示要么隐藏之后不会再改变显示隐藏状态的情况,v-if更加的合理,
因为如果默认就是隐藏,相当于dom一次都不用创建,如果默认是显示,v-if和v-show效果完全一样。
配置路由元信息:
路由传参:
1、路由传参,参数有几种写法?
params参数:属于路径当中的一部分,需要注意,在配置路由的时候,需要占位。
query参数:不属于路径当中的一部分,类似于Ajax中的queryString /home?k=v&kv=,不需要占位。
1)字符串形式
{
path:"/Search/:keyword",//占位
name:Search,
component:Search,
meta:{show:true}
},
goSearch(){
this.$router.push("/search/"+this.keyword+"?k="+this.keyword.toUppercase());
}
<div>
<h1>params参数-----{{$route.params.keyword}}</h1>
<h1>query参数------{{$route.query.k}}</h1>
</div>
2)模板字符串
goSearch(){
this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUppercase()}`);
}
3)对象(常用写法!)
先给路由命名!
goSearch(){
this.$router.push({name:"search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}});
}
路由传参相关面试题:
1、路由传递参数(对象写法)path是否可以结合params参数一起使用?
答:不可以。
路由跳转传参的时候,对象的写法可以是name\path形式,但是要注意,path这种写法不能与params一起使用。
2、如何指定params参数可传可不传?
答:如果路由要求传递params参数,但是你就不传递params参数,发现一件事情,url会有问题。比如:配置路由的时候,占位了(params参数),但是路由跳转的时候就不传递,路径会出错。
如何指定params参数可以传递或不传递呢?在配置路由的时候在占位的后面加上一个问号?例如:path:"/search/:keyword?",
3、params参数可以传递也可以不传递,但是如果传递是空串,如何解决? 答:使用undefined解决:params参数可以传递、不传递(空的字符串)
this.$router.push({name:'search',params:{keyword:''||undefined},query:{k:this.keyword.toUpperCase()}})
如果指定name与params配置, 但params中数据是一个"", 无法跳转,路径会出问题
4、 路由组件能不能传递props数据?
答:可以。
第一种写法:
布尔值写法:params(只能传递params参数) props:true,
第二种写法:
对象写法:额外的给路由组件传递一些props props:{a:1,b:2},
第三种写法:
函数写法:可以params参数、query参数,通过props传递给路由组件
props:($route)=>{
return {keyword:$route.params.keywowrd,k:$route.query.k};
}
编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误? 注意:编程式导航(push|replace)才会有这种情况的异常,声明式导航是没有这种问题,因为声明式导航内部已经解决这种问题。 这种异常,对于程序没有任何影响的。 为什么会出现这种现象: 由于vue-router最新版本3.5.2,引入了promise,当传递参数多次且重复,会抛出异常,因此出现上面现象, 第一种解决方案:是给push函数,传入相应的成功的回调与失败的回调,可以捕获到当前错误,可以解决。
goSearch(){ this.$router.push({name:"search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},()=>{},()=>{});}
第一种解决方案可以暂时解决当前问题,但是以后再用push|replace还是会出现类似现象,因此我们需要从‘根’治病;
push:VueRouter类的一个实例,
2.4.3全局组件
2.5axios二次封装
为什么需要进行二次封装axios?
请求拦截器、响应拦截器,可以在发请求前处理一些业务、响应拦截器,当服务器数据返回以后,可以处理一些事情。
npm install --save axios
//对axios进行二次封装
import axios from "axios";
//1.利用axios对象的方法create,去创建一个axios实例
//2.request就是axios,只不过稍微配置一下
const requests=axios.create({
//配置对象
//基础路径,发请求的时候,路径当中会出现api
baseURL:"/api",
//代表请求超时的时间5s
timeout:5000,
});
// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
//config:配置对象,对象里面有一个属性很重要,headers请求头
...
return config;
});
//响应拦截器
requests.interceptors.response.use((res)=>{
//成功的回调函数:服务器相应数据回来以后,响应拦截器可以检测到,可以做一些事情
...
return res.data;
},(error)=>{
return Promise.reject(new Error('fail'));
});
//对外暴露
export default requests;
2.6接口统一管理
2.6.1跨域问题
https://blog.csdn.net/qq_51066068/article/details/126132149
什么是跨域:协议、域名、端口号不同,称之为跨域,具体请百度。
代理跨域:
2.7nprogress进度条插件的使用
npm install --save nprogress
//引入进度条
import nprogress from 'nprogress';
import 'nprogress/nprogress.css';
//start:进度条开始 done:进度条结束
2.8 vuex状态管理库
vuex是什么?官方提供的一个插件,状态管理库,集中式管理项目中组件共用的数据。并不是所有的项目都需要vuex。
state、mutations、actions、getters、modules
npm install vuex@next --save
新建store文件夹->index.js
import Vue from 'vue'
import Vuex from 'vuex'
//需要使用插件一次
Vue.use(Vuex);
//对外暴露Store类的一个实例
export default new Vuex.Store({
// 仓库存储数据的地方
state:{
},
//修改state的唯一方法
mutations:{
},
//处理action,可以书写自己的业务逻辑,也可以处理异步
//这里可以书写逻辑 但是不能直接修改state
actions:{
},
//理解为计算属性,用于简化仓库数据,让组件获取仓库的数据方便
getters:{
}
});
入口文件注册:
vuex中 this.$store.dispatch() 与 this.$store.commit()方法的区别:
this.$store.dispatch() 与 this.$store.commit()方法的区别总的来说他们只是存取方式的不同,两个方法都是传值给vuex的mutation改变state
this.$store.dispatch() :含有异步操作,例如向后台提交数据,写法:this.$store.dispatch(‘action方法名’,值)
this.$store.commit():同步操作,,写法:this.$store.commit(‘mutations方法名’,值)
commit:同步操作
存储 this.$store.commit('changeValue',name)
取值 this.$store.state.changeValue
dispatch:异步操作
存储 this.$store.dispatch('getlists',name)
取值 this.$store.getters.getlists
Cannot read properties of undefined (reading 'dispatch')
报错解决:
vuex安装版本太高!
卸载vuex:npm uninstall vuex
vue2安装vuex版本:npm install vuex@3 --save
vuex中Modules的使用详解:
https://www.jb51.net/article/244804.htm
各种小仓库=》大仓库
1、首先大仓库的配置:
引入vuex,使用vuex插件,
引入所有的小仓库,将小仓库在模块里面注册,对外暴露仓库
2、小仓库的配置
const state={};const mutations={};const actions={};const getters={}
在actions里面用async和await写方法来调用接口函数reqCategoryList()(记得import进来api),然后commit给mutations来修改state里的数据。
3、在vue页面
首先页面组件通过mouted挂载完毕,向服务器发送请求数据,将得到的数据存在仓库,也就是这句 this.$store.dispatch('categoryList');
然后在组件中使用到categoryList数据的时候用到计算属性computed,引入mapState插件,相关属性从state里拿数据。(这里state是大仓库,state.home才是此时需要的小仓库)
3、防抖与节流
本质上是优化高频率执行代码的一种手段 如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用throttle(防抖)和debounce(节流)的方式来减少调用频率。
定义:
-
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
-
防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
lodash插件:里面封装函数的防抖与节流的业务,如果想要自己写【闭包+延迟器】
4、过渡动画
例子:开发Search模块中的Typenav商品分类菜单(过渡动画效果)
过渡动画:前提组件|元素务必要有v-if|v-show指令才可以进行过渡动画
https://www.yisu.com/zixun/166849.html
https://www.wubin.work/blog/articles/16
5、mock.js模拟数据
印记中文网站有各种库https://docschina.org/ 搜mock.js
# 安装
npm install mockjs
使用步骤:
1)在项目src文件夹中创建mock文件夹
2)准备JSON数据(mock文件夹中创建相应的JSON文件)
3)把mock数据需要的图片放置到public文件夹中【public文件夹在打包的时候,会把相应的资源原封不动的打包到dist文件夹中】
4)创建mockServe.js通过mockjs插件实现模拟数据
5)把mockServe.js文件在入口文件中引入(至少需要执行一次才能模拟数据)
6)模拟请求 (在api文件夹下创建新文件mockAjax.js)
7)在商品列表页面通过vuex发起请求,将数据仓储在对应仓库中
6、Swiper基本使用
npm install swiper -S //安装最新版本
npm install swiper@4.5.1 --save-dev //安装4版本
mounted:组件挂载完毕,正常说组件结构(DOM)已经全有了
为什么swiper实例在mounted当中直接书写不可以?
因为结构还没有完整
$nextTick:在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用这个方法,获取更新后的 DOM。
$nextTick:可以保证也页面中的结构一定是有的,经常和很多插件一起使用【都需要DOM存在了】|
7、组件通信的方式有哪些?
props:用于父子组件通信
自定义事件:@on @emit 可以实现子给父通信
全局事件总线:$bus 全能
pubsub-js:vue几乎不用
插槽
vuex
8、生命周期
9、全局事件总线 Vue.prototype.$bus
由于Vue3中的mian.js文件中,已经不提供Vue2的
Vue2:
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this // 安装全局事件总线
}
})
Vue3:
createApp(App).mount('#app')
安装
npm install --save vue3-eventbus
挂载
import eventBus from 'vue3-eventbus'
app.use(eventBus)
使用
// Button.vue
import bus from 'vue3-eventbus'
export default {
setup() {
bus.emit('foo', { a: 'b' })
}
}
引入后:
main.js中使用 use() 方法
import eventBus from 'vue3-eventbus'
createApp(App).use(eventBus).mount('#app')
其它文件引入后, 使用 bus.on() 替代 原本 this.$bus.$on() 写法
以此类推 bus.emit()、 bus.off()、 bus.on()
import bus from 'vue3-eventbus'
mounted(){
//Vue2
this.$bus.$on()
//现在
bus.on()
}
来源:https://blog.csdn.net/qq_36164225/article/details/126641090