Vue2.0项目入门笔记(1)23.5.18

meifirst / 2023-05-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文件

image-20221115090026862

2.3 src文件夹简写方法,配置别名

image-20221115090736930

@代表的是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使用组件的步骤(非路由组件)

  • 创建或者定义

  • 引入

    image-20221115093221266

     

  • 注册

    image-20221115093925911

  • 使用

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入口文件中引入并注册!

image-20221115101938316

最后在组件中用router-view标签显示路由:

image-20221115102046926

在main.js里面注册完路由,组件身上都拥有$route,$router属性,

$route和$router区别:

$route:一般获取路由信息【路径、query、params等等】

$router:一般进行编程式导航进行路由跳转【push|replace】

重定向:

在项目跑起来的时候,访问/,立马让他定向到首页

image-20221115103331496

路由的跳转

路由的跳转有两种形式:

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效果完全一样。

配置路由元信息:

image-20221115105642024

image-20221115105752003

路由传参:

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)对象(常用写法!)

image-20221116171507460

先给路由命名!

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,

image-20221115145331487

第二种写法:

对象写法:额外的给路由组件传递一些props props:{a:1,b:2},

image-20221115145654242

第三种写法:

函数写法:可以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类的一个实例,

image-20221115151901858

2.4.3全局组件

image-20221115153014406

image-20221115153217480

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

什么是跨域:协议、域名、端口号不同,称之为跨域,具体请百度。

代理跨域:

image-20221115162659566

2.7nprogress进度条插件的使用

npm install --save nprogress
//引入进度条
import nprogress from 'nprogress';
import 'nprogress/nprogress.css';
//start:进度条开始 done:进度条结束

image-20221115163259974

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:{

  }
});

入口文件注册:

image-20221115164836168

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')

报错解决:

image-20221116134759887

image-20221116134906911

vuex安装版本太高!

卸载vuex:npm uninstall vuex

vue2安装vuex版本:npm install vuex@3 --save

 

vuex中Modules的使用详解:

https://www.jb51.net/article/244804.htm

各种小仓库=》大仓库

1、首先大仓库的配置:

引入vuex,使用vuex插件,

引入所有的小仓库,将小仓库在模块里面注册,对外暴露仓库

image-20221116145946417

2、小仓库的配置

image-20221116150209625

const state={};const mutations={};const actions={};const getters={}

在actions里面用async和await写方法来调用接口函数reqCategoryList()(记得import进来api),然后commit给mutations来修改state里的数据。

3、在vue页面

image-20221116150709745

首先页面组件通过mouted挂载完毕,向服务器发送请求数据,将得到的数据存在仓库,也就是这句 this.$store.dispatch('categoryList');

然后在组件中使用到categoryList数据的时候用到计算属性computed,引入mapState插件,相关属性从state里拿数据。(这里state是大仓库,state.home才是此时需要的小仓库)

3、防抖与节流

本质上是优化高频率执行代码的一种手段 如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。

为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用throttle(防抖)和debounce(节流)的方式来减少调用频率。

定义:

  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

  • 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

lodash插件:里面封装函数的防抖与节流的业务,如果想要自己写【闭包+延迟器】

image-20221116161826940

image-20221116161844380

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文件)

image-20221117153538308

3)把mock数据需要的图片放置到public文件夹中【public文件夹在打包的时候,会把相应的资源原封不动的打包到dist文件夹中】

image-20221117153722606

4)创建mockServe.js通过mockjs插件实现模拟数据

image-20221117153828531

5)把mockServe.js文件在入口文件中引入(至少需要执行一次才能模拟数据)

image-20221117153927619

6)模拟请求 (在api文件夹下创建新文件mockAjax.js)

image-20221117154041350

7)在商品列表页面通过vuex发起请求,将数据仓储在对应仓库中

image-20221117154351513

image-20221117154420403

6、Swiper基本使用

npm install swiper -S   //安装最新版本
npm install swiper@4.5.1 --save-dev   //安装4版本

mounted:组件挂载完毕,正常说组件结构(DOM)已经全有了

为什么swiper实例在mounted当中直接书写不可以?

因为结构还没有完整

image-20221117170336326

image-20221117172254228

$nextTick:在下次DOM更新循环结束之后执行延迟回调。在修改数据之后,立即使用这个方法,获取更新后的 DOM。

$nextTick:可以保证也页面中的结构一定是有的,经常和很多插件一起使用【都需要DOM存在了】|

7、组件通信的方式有哪些?

props:用于父子组件通信

自定义事件:@on @emit 可以实现子给父通信

全局事件总线:$bus 全能

pubsub-js:vue几乎不用

插槽

vuex

8、生命周期

9、全局事件总线 Vue.prototype.$bus

由于Vue3中的mian.js文件中,已经不提供Vue2的挂载方式, Vue.prototype.$bus = this

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

10、模板字符串

image-20221119083640880