vue项目练手-尚品汇

1.创建项目

我选择用vue-cli图形化界面初始化项目

在文件夹下cmd打开命令行,输入vue ui

 打开vue-cli图形化界面,如下,选择创建

 填写项目名称,并初始化仓库

 下一步是预设

 这里可以选择之前的,也可以自己手动进行配置,我选择手动,我选择了这些配置

 然后创建项目,可以保存为预设,下次可以直接用,就不用再一步步配置了

 创建时间会有点久,创建完成以后就是这种界面

 接下来是运行项目,选择左侧的任务-serve-运行

当如下图显示时就点击启动app

 出现如下界面表示项目创建成功

项目创建好以后,用vscode打开,来看一下项目的文件构成

node-modules:项目依赖

public:一般放置一些静态资源(图片) ,这些资源在webpack进行打包的时候会原封不动的打包到dist文件夹中

src:程序员源代码文件夹

      assets:一般也是放置静态资源(一般放置多个组件公用的静态资源),这里面的资源在                              webpack进行打包的时候会被当做一个模块,打包在js文件里面

      components:一般放置的是非路由组件(或是一些常用的全局组件)

      App.vue:唯一的根组件

      main.js:程序入口文件,整个程序当中最先执行的文件

babel.config.js:配置文件(babel相关)

package.json:记录项目叫什么,项目当中有哪些依赖..  项目怎么运行

package-lock.json:缓存性文件

还需要对项目进行的其他一些配置

①项目运行起来以后,浏览器自动打开

 ②关闭eslint代码语法校验工具

在项目根目录下创建vue.config.js文件(一定要是这个名字),并写入以下内容

module.exports = {
  // 关闭eslint
  lintOnSave: false,
};

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

在项目根目录下创建jsconfig.json文件,并进行以下配置

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

在进行完以上配置后,建议重新运行一下项目,看项目是否可以正常运行,也就是在图形化面板中的serve那点击停止然后再点击运行,运行完成后再点击启动app,如果跟上面运行的一样,证明配置正确。

在开发项目的时候步骤:

1.书写静态页面(html+css)

2.拆分组件

3.获取服务器的数据动态展示

4.完成响应的动态业务逻辑

2.开发项目时遇到的问题

1.项目组件中采用了less样式,但是浏览器不识别less样式,需要安装less和less-loader处理less,把less变成css

因为less-loader版本太高也不太好,所以我选择用命令行安装指定版本

npm i less less-loader@5

如果想让组件识别less,就要在style标签内加上lang="less",即<style lang="less">

2.使用组件的步骤

①创建/定义

②引入

③注册

④使用

 3.搭建路由组件

需要安装vue-router,这里我使用命令行安装

npm i --save vue-router

在src目录下新建pages/views文件夹,这个文件夹通常放置路由组件

4.配置路由

在src目录下新建一个router文件夹,项目中配置的路由一般放置在router文件夹内

 配置好路由以后需要指定路由组件展示的位置

 5.路由组件与非路由组件的区别

①路由组件一般放在pages/views文件夹,非路由组件一般放在component文件夹

②路由组件一般在router文件夹中进行注册(使用的就是组件名字),非路由组件在使用的时候一般都是以标签的形式

③注册完路由,不管是路由还是非路由组件,身上都有$route、$router属性

    $route:一般获取路由信息(路径、query、params)

    $router:一般进行编程式导航路由跳转(push/replace)

6.路由的跳转形式

声明式导航:router-link,可以进行路由的跳转

编程式导航:利用组件实例的$router.push/replace,可以进行路由的跳转(声明式导航能做的,编程式导航都能做)

7.控制组件的显示与隐藏

v-if:真正的条件渲染,每次切换都是组件的销毁和重建,有较高的切换开销,如果切换较少,推荐使用v-if

v-show:实质上是通过布尔值true和false来控制组件的显示与隐藏,即display:none和display:block;如果需要频繁使用切换,选择v-show更好,有较高的初始渲染开销

给路由添加路由元信息【meta】,不能瞎写

 8.路由传参,参数有几种写法

params参数:属于路径当中的一部分,在配置路由的时候需要占位,即/search/params参数

query参数:不属于路径当中的一部分,类似于ajax中的queryString  /home?k=v&k=v,不需要占位,

路由传递参数:

第一种:字符串形式

this.$router.push("/search/"+this.keyword+"?k="+this.keyword)

 第二种:模板字符串

this.$router.push(`/search/${this.keyword}?k=${this.keyword}`)

第三种:对象

// 这里的name属性需要在配置路由的index.js文件中配置
//即{path:'/search',component:Search,name:'search'}
this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword}})

9.路由传参相关面试题

①路由传递参数(对象写法)path是否可以结合params参数一起使用?

答:路由跳转传参的时候,对象的写法可以是name/path形式,但是path这种写法是不能与params参数一起使用的,会出错,可以与query一起使用

// "/search"后面带了/:keyword说明是要求传params参数的意思
{ path: "/search/:keyword", component: Search, meta: { show: true } },

this.$router.push({
          path: '/search',
          params: { keyword: this.keyword },
          query: { k: this.keyword.toUpperCase() }   
              })

②如何指定params参数可传不可传?

答:在配置路由的时候,在占位后面加上一个?就可以了

如果路由要求传递params参数,但是就不传,会导致跳转的url出错 ,不加?之前:

// :keyword后面加上?说明这个params参数keyword可传可不传 
{ path: "/search/:keyword?", component: Search, meta: { show: true } },

在keyword后面加上?以后 :

③params参数可以传递也可以不传递,但是如果传递是空串,如何解决?

答:使用undefined解决

this.$router.push({name:'search',params:{keyword:''||undefined},query:{k:this.keyword}})

如果传的params为空,且没有加undefined,则url会出错

④路由组件能不能传递props数据?

能传递,有三种方式:

(1)布尔值写法:只能传递params

{
      path: "/search/:keyword?",
      component: Search,
      meta: { show: true },
      name: "search",
      props:true
    }

(2)对象写法 :props:{a:1,b:2}

// 路由配置文件index.js
{
      path: "/search/:keyword?",
      component: Search,
      meta: { show: true },
      name: "search",
      props:{a:1,b:2}
    }

// 组件.vue
<script>
  export default {
     // 在组件这里通过props接收,可以通过插值表达式{{}}直接渲染在页面上
     props:['a','b']
  }

</script>

(3)函数写法:可以把params参数,query参数通过props传给路由组件

{
      path: "/search/:keyword?",
      component: Search,
      meta: { show: true },
      name: "search",
      props:($route)=>({keyword:$route.params.keyword,k:$route.query.k})
    }

10.重写push和replace方法(可以解决编程式路由跳转到当前路由参数不变,多次执行抛出NavigationDuplicated的警告)

// 路由配置文件index.js

//需要重写VueRouter.prototype原型对象身上的push|replace方法
//先把VueRouter.prototype身上的push|replace方法进行保存一份
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
//重写VueRouter.prototype身上的push方法
VueRouter.prototype.push = function (location, resolve, reject) {
  //第一个形参:路由跳转的配置对象(query|params)
  //第二个参数:undefined|箭头函数(成功的回调)
  //第三个参数:undefined|箭头函数(失败的回调)
  if (resolve && reject) {
    //push方法传递第二个参数|第三个参数(箭头函数)
    //originPush:利用call修改上下文,变为(路由组件.$router)这个对象,第二参数:配置对象、第三、第四个参数:成功和失败回调函数
    originPush.call(this, location, resolve, reject);
  } else {
    //push方法没有产地第二个参数|第三个参数
    originPush.call(
      this,
      location,
      () => {},
      () => {}
    );
  }
};
//重写VueRouter.prototype身上的replace方法
VueRouter.prototype.replace = function (location, resolve, reject) {
  //第一个形参:路由跳转的配置对象(query|params)
  //第二个参数:undefined|箭头函数(成功的回调)
  //第三个参数:undefined|箭头函数(失败的回调)
  if (resolve && reject) {
    //push方法传递第二个参数|第三个参数(箭头函数)
    //originPush:利用call修改上下文,变为(路由组件.$router)这个对象,第二参数:配置对象、第三、第四个参数:成功和失败回调函数
    originReplace.call(this, location, resolve, reject);
  } else {
    //push方法没有产地第二个参数|第三个参数
    originReplace.call(
      this,
      location,
      () => {},
      () => {}
    );
  }
};

11.call和apply相同点与不同点

相同点:都可以调用函数一次,都可以篡改函数的上下文一次

不同点:call与apply传递参数,call传递多个参数用逗号分隔,apply传递数组

12.注册全局组件

当页面拆分出来的某个组件多次出现在别的页面的时候,就把这个组件注册为全局组件,只需要注册一次,就可以在项目的任意地方使用。

在main.js中注册全局组件TypeNav

 13.利用postman工具测试接口

14.axios的二次封装

请求拦截器:可以在发起请求之前处理一些业务

响应拦截器:当服务器返回数据之后,可以处理一些业务

①先下载axios

npm i --save axios

 ②在src下新建api文件夹,再新建request.js文件对axios进行二次封装

// 对于axios进行二次封装
import axios from "axios";
// 利用axios对象的方法create,创建一个axios实例
// 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("false"));
  }
);
// 对外暴露
export default requests;

 15.接口的统一管理

项目很小:完全可以在组件的生命周期函数中发请求

项目很大:axios.get('xxx')

①在src下的api文件夹下新建index.js对所有的api进行统一管理

// 对api进行统一管理
import requests from "./request";

// 三级联动接口
// 请求地址 /api/product/getBaseCategoryList
// 请求方式 get
// 请求参数 无
// axios发送请求返回结果Promise对象
// 这种是不传递参数的请求
export const reqCategoryList = () => {
  return requests({ url: "/product/getBaseCategoryList", method: "get" });
};



// 获取搜索模块数据 需要传递参数
// 当前这个接口,给服务器传递一个默认参数,至少是个空对象
export const reqGetSearchInfo = (params) => {
  return requests({ url: "/list", method: "post", data: params });
};

16.跨域问题

什么是跨域:协议、域名、端口号不同请求,称之为跨域

http://localhost:8080/#/home   ----前端项目本地服务器

http://39.38.123.211                 ----后台服务器

像上面的本地服务器和后台服务器之间就存在跨域问题

跨域的解决方案:JSONP、CROS、代理

例:使用代理服务器解决

在项目根目录下的webpack.config.js/vue.config.js文件中进行如下配置

// 代理跨域
  devServer: {
    proxy: {
      // 当浏览器的url地址中遇到api时
      //会通过这个代理跨域去寻找target这个后台服务器去获取数据
      "/api": {
        target: "http://39.98.123.211",
      },
    },
  },

注:更改配置文件后记得重新启动一下项目

17.nprogress进度条的使用

①首先下载nprogress

npm i --save nprogress

②因为是请求发起的时候使用进度条,服务器的数据返回后进度条消失,所以要把nprogress进度条放在请求拦截器和响应拦截器中使用

// 在request.js文件中
// 引入进度条nprogress
import nprogress from "nprogress";
// 引入进度条样式
import "nprogress/nprogress.css";

// 请求拦截器
requests.interceptors.request.use((config) => {
  // 进度条开始
  nprogress.start();
  // config:配置对象,对象里面有一个属性很重要,headers请求头
  return config;
});
// 响应拦截器
requests.interceptors.response.use(
  (res) => {
    // 进度条结束
    nprogress.done();
    // 响应成功的回调函数,返回获取到的数据
    return res.data;
  },
  (error) => {
    // 响应失败的回调函数
    return Promise.reject(new Error("false"));
  }
);

 plus:进度条的颜色可以更改,在node_modules文件夹下的nprogress文件夹下的nprogress.css中更改如下的样式

18.vuex的使用

vuex:状态管理模式,采用集中式存储管理所有组件状态

①下载安装vuex

npm i --save vuex

②在src目录下创建store文件夹,在store文件夹下创建index.js文件

import Vue from "vue";
import Vuex from "vuex";
// 需要使用插件一次
Vue.use(Vuex);
// 引入小仓库
import home from "./home/index.js";
import search from "./search/index.js";
// 对外暴露Store类的实例
export default new Vuex.Store({
  // 模块:把小仓库进行合并变成大仓库
  modules: {
    home,
    search,
  },
});

③在入口文件main.js中注册仓库

 ④采用集中式管理,为了方便所以创建各个模块的小仓库,比方说下面建立的home模块的仓库

// home模块的小仓库
import { reqCategoryList } from "@/api";
// state:仓库存储数据的地方
const state = {
  // 分类列表
  categoryList: [],
};
// mutations:修改state的唯一手段
const mutations = {
  CATEGORYLIST(state, categoryList) {
    state.categoryList = categoryList;
  },
};
// action:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {
  // 通过api里面的接口函数调用,向服务器发请求,获取服务器的数据
  async categoryList({ commit }) {
    let result = await reqCategoryList();
    console.log(result);
    if (result.code == 200) {
      commit("CATEGORYLIST", result.data);
    }
  },
};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {};
export default {
  state,
  mutations,
  actions,
  getters,
};

19.在统一管理接口的背景下,项目发起请求,获取服务器数据的过程和步骤

①在当前需要获取数据的组件内

plus:当请求要传递参数时

 ②store文件夹下的仓库(看当前需要获取数据的组件使用哪个仓库)

plus:当使用到getters时

③在当前需要获取数据的组件内

plus:使用到getters时,组件中获取数据就变成了

 页面渲染

20.防抖与节流

卡顿现象:事件触发非常频繁,而且每一次的触发,回调函数都要去执行,如果时间很短,而回调函数内部有计算,可能会出现浏览器卡顿

节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。用户操作很频繁,但是把频繁的操作变为少量操作,可以让浏览器有充裕的事件解析代码。

防抖:前面所有的触发都被取消,最后一次执行在规定的时间之后才会触发,即如果连续快速的触发,只会执行一次。用户操作很频繁,但是只执行一次。

lodash插件:里面封装函数的防抖与节流业务【闭包+延迟器】

21.路由跳转与传递参数

在这里避免因为鼠标滑动过于频繁导致页面出现卡顿现象,使用了编程式导航,点击事件结合自定义属性,把点击事件放在了a标签的父标签上,为a标签添加了自定义属性categoryname和category*id

22.过渡动画

前提:组件/元素务必要有v-if/v-show指令才可以进行过渡动画

在要执行过渡动画效果的标签外包裹<transition>标签,如下

23.mockjs模拟数据

如果想mock一些虚拟数据,需要用到mockjs插件

mockjs发的请求不会向后台服务器发送,会被浏览器拦截,模拟的数据用的时候当做真实数据就好

①下载安装mockjs插件

npm install mockjs

②使用步骤

第一步:在src目录下创建mock文件夹,这个文件夹是用来提供假数据的

第二步:准备JSON假数据,在mock文件夹中创建相应的json文件(数据弄完之后记得格式化一下json文件,有空格的话项目跑不起来)

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

第四步:在mock文件夹下创建mockServe.js文件,通过mockjs模块实现模拟数据

// 先引入mockjs模块
import Mock from "mockjs";
// 把JSON数据格式引入进来
// banner.json和floor.json没有对外暴露,但是在这里可以引入
// 原因:webpack默认对外暴露:图片、JSON数据格式
import banner from "./banner.json";
import floor from "./floor.json";
// mock数据 第一个参数:请求地址 第二个参数:请求数据
Mock.mock("/mock/banner", { code: 200, data: banner }); // 模拟首页大的轮播图的数据
Mock.mock("/mock/floor", { code: 200, data: floor }); // 模拟首页电梯导航的数据

第五步:在入口文件main.js中引入mockServe.js文件(至少需要执行一次才能模拟数据)

注:mock发请求不能再利用之前的request.js文件,因为它们的根路径不同,一个/mock,一个/api,所以创建mock专属的mockRequest.js文件

// 对于axios进行二次封装
import axios from "axios";
// 引入进度条nprogress
import nprogress from "nprogress";
// 引入进度条样式
import "nprogress/nprogress.css";
// 利用axios对象的方法create,创建一个axios实例
// request其实就是axios,就是稍微配置一下
const mockRequests = axios.create({
  // 配置对象
  // 基础路径,发请求的时候,路径中会出现api
  baseURL: "/mock",
  // 代表请求超时时间为5s
  timeout: 5000,
});
// 请求拦截器
mockRequests.interceptors.request.use((config) => {
  // 进度条开始
  nprogress.start();
  // config:配置对象,对象里面有一个属性很重要,headers请求头
  return config;
});
// 响应拦截器
mockRequests.interceptors.response.use(
  (res) => {
    // 进度条结束
    nprogress.done();
    // 响应成功的回调函数,返回获取到的数据
    return res.data;
  },
  (error) => {
    // 响应失败的回调函数
    return Promise.reject(new Error("false"));
  }
);
// 对外暴露
export default mockRequests;

在index.js中处理请求

24.swiper轮播图插件的使用

(1)html页面使用swiper插件

①下载安装

②使用步骤

第一步:引包(js/css)swiper-bundle.min.js和swiper-bundle.min.css

<link rel="stylesheet" href="dist/css/swiper-bundle.min.css">

<script src="dist/js/swiper-bundle.min.js"></script>

第二步:页面中的结构务必要有

<div class="swiper">
    <div class="swiper-wrapper">
        <div class="swiper-slide">Slide 1</div>
        <div class="swiper-slide">Slide 2</div>
        <div class="swiper-slide">Slide 3</div>
    </div>
    <!-- 如果需要分页器 -->
    <div class="swiper-pagination"></div>
    
    <!-- 如果需要导航按钮 -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
    
    <!-- 如果需要滚动条 -->
    <div class="swiper-scrollbar"></div>
</div>

第三步(前提:页面当中务必要有结构):new swiper实例(轮播图添加动态效果) 

(2)组件中使用swiper插件

①下载安装

npm i --save swiper@5

②使用步骤

第一步:引包

在使用轮播图的组件中引入swiper

因为在项目中有多个组件使用轮播图,所以在入口文件main.js中引入样式

第二步:页面中的轮播图结构要有

第三步(前提:页面当中务必要有结构):new swiper实例(轮播图添加动态效果) 

这里有个问题,new swiper实例应该放在哪里,因为dispatch当中涉及到异步语句,导致v-for遍历的时候页面结构还不完整,因此不可以直接放到mounted()生命周期函数里

解决方法一:在mounted()生命周期函数里使用setTimeout定时器

setTimeout(()=>{
         var mySwiper = new Swiper ('.swiper', {
         direction: 'vertical', // 垂直切换选项
         loop: true, // 循环模式选项

         // 如果需要分页器
         pagination: {
         el: '.swiper-pagination',
         },

         // 如果需要前进后退按钮
         navigation: {
         nextEl: '.swiper-button-next',
         prevEl: '.swiper-button-prev',
         },

         // 如果需要滚动条
         scrollbar: {
         el: '.swiper-scrollbar',
         },
         })
      },2000)

解决方法二(最完美的方法):使用watch监听器+nextTick()(watch监听器与methods并排写)

// 使用watch监听器(watch监听器的使用只能保证数据已经有了,但是不能保证v-for执行完毕,即结构渲染结束)
    watch: {
      // 监听bannerList数据的变化,数据从空到有四个元素
      bannerList: {
        handler(newValue, oldValue) {
          // 如果执行了handler方法,代表数据已经发生了变化
          // nextTick():在下次DOM更新,循环结束以后,执行延迟回调,在修改数据之后,立即使用这个方法,获取更新后的DOM
          this.$nextTick(() => {
            var mySwiper = new Swiper('.swiper-container', {
              // direction: 'vertical', // 垂直切换选项
              loop: true, // 循环模式选项
              // 如果需要分页器
              pagination: {
                el: '.swiper-pagination',
                // 点击小圆圈也可以进行切换图片
                clickable: true
              },
              // 如果需要前进后退按钮
              navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
              },
              // 如果需要滚动条
              scrollbar: {
                el: '.swiper-scrollbar',
              },
            })
          })
        }
      }
    }

25.日常工作中的工作步骤

①书写静态页面+静态组件拆分(pages/views文件夹)

②发请求获取数据(写api)(api文件夹)

③仓库存储数据(vuex三连环)(store文件夹)

④组件获取仓库数据,动态展示数据(pages/views文件夹)

26.路由组件被复用的时候,要在复用他的父组件中进行向仓库请求获取数据的操作

父组件向子组件传值

27.组件通信的方式有哪些?

props:用于父子组件通信

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

全局事件总线:$bus 全能

pubsub-js:vue当中几乎不用 全能

插槽

vuex

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值