vue项目中的技术

1.先构建项目

$ npm install -g @vue/cli  (安装vue-cli)
$ vue create .(创建项目在根目录下)
$ vue create +项目名 (创建项目在自定义项目名目录下)

2.移动端自适应配置 (rem+flex布局)

  • rem配置(全局引入的文件在main.js中引入)

    • 网易方案

      function font () {
        document.documentElement.style.fontSize = document.documentElement.clientWidth / 3.75  + 'px'
      }
      
      font() // 表示页面一开启就转换单位 
      
      
      window.onresize = font  // 表示页面尺寸发生改变时,再次计算rem
      
    • 淘宝方案

      (function(designWidth, maxWidth) {
      	var doc = document,
      	win = window,
      	docEl = doc.documentElement,
      	remStyle = document.createElement("style"),
      	tid;
      
      	function refreshRem() {
      		var width = docEl.getBoundingClientRect().width;
      		maxWidth = maxWidth || 540;
      		width>maxWidth && (width=maxWidth);
      		var rem = width * 100 / designWidth;
      		remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
      	}
      
      	if (docEl.firstElementChild) {
      		docEl.firstElementChild.appendChild(remStyle);
      	} else {
      		var wrap = doc.createElement("div");
      		wrap.appendChild(remStyle);
      		doc.write(wrap.innerHTML);
      		wrap = null;
      	}
      	//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
      	refreshRem();
      
      	win.addEventListener("resize", function() {
      		clearTimeout(tid); //防止执行两次
      		tid = setTimeout(refreshRem, 300);
      	}, false);
      
      	win.addEventListener("pageshow", function(e) {
      		if (e.persisted) { // 浏览器后退的时候重新计算
      			clearTimeout(tid);
      			tid = setTimeout(refreshRem, 300);
      		}
      	}, false);
      
      	if (doc.readyState === "complete") {
      		doc.body.style.fontSize = "16px";
      	} else {
      		doc.addEventListener("DOMContentLoaded", function() {
      			doc.body.style.fontSize = "16px";
      		}, false);
      	}
      })(375, 750); 
      
      // 备注: 这里的375本身就应该写成750 ,但是写成750之后,我们设计稿的尺寸要/50,不好算,我就想,除以100更好算,所以我改成了375
      
    • 阿里方案

      /* 
        通过js来动态添加rem 
      */
      
      (function(designWidth, maxWidth) {
      	var doc = document,
      	win = window,
      	docEl = doc.documentElement,
      	remStyle = document.createElement("style"),
      	tid;
      
      	function refreshRem() {
      		var width = docEl.getBoundingClientRect().width;
      		maxWidth = maxWidth || 540;
      		width>maxWidth && (width=maxWidth);
      		var rem = width * 100 / designWidth;
      		remStyle.innerHTML = 'html{font-size:' + rem + 'px;}';
      	}
      
      	if (docEl.firstElementChild) {
      		docEl.firstElementChild.appendChild(remStyle);
      	} else {
      		var wrap = doc.createElement("div");
      		wrap.appendChild(remStyle);
      		doc.write(wrap.innerHTML);
      		wrap = null;
      	}
      	//要等 wiewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
      	refreshRem();
      
      	win.addEventListener("resize", function() {
      		clearTimeout(tid); //防止执行两次
      		tid = setTimeout(refreshRem, 300);
      	}, false);
      
      	win.addEventListener("pageshow", function(e) {
      		if (e.persisted) { // 浏览器后退的时候重新计算
      			clearTimeout(tid);
      			tid = setTimeout(refreshRem, 300);
      		}
      	}, false);
      
      	if (doc.readyState === "complete") {
      		doc.body.style.fontSize = "16px";
      	} else {
      		doc.addEventListener("DOMContentLoaded", function() {
      			doc.body.style.fontSize = "16px";
      		}, false);
      	}
      })(375, 750); 
      
      // 备注: 这里的375本身就应该写成750 ,但是写成750之后,我们设计稿的尺寸要/50,不好算,我就想,除以100更好算,所以我改成了375
      

3.构建项目目录

src/layout/index.vue 项目的布局外壳

src/components 项目的公共组件在layout中使用

src/utils 项目的公共封装库

src/pages 项目的路由路径对应的组件

src/store 状态管理vuex的配置文件夹

src/router 创建路由配置文件夹

mock.service 数据模拟

4.配置vue.config.js文件(包括数据反向代理)

const path = require('path')

module.exports = {
   
  chainWebpack: config => {
    config.resolve.alias
      .set('@', path.join( __dirname, './src' ))
      .set('assets', path.join( __dirname, './src/assets' ))
      .set('components', path.join( __dirname, './src/components' ))
  },
  //反向代理(此处用了猫眼,亲亲网数据)
  devServer: {
    open: true,
    proxy: {
      '/ajax': {
        target: 'http://m.maoyan.com',
        changeOrigin: true 
      },
      '/index.php': {
        target: 'http://www.qinqin.net',
        changeOrigin: true 
      }
    }
  }
}

5.重置样式(assets/stylesheets/reset.css)

百度去搜

6.数据请求封装request.js

记得安装axios插件 $ yarn add axios

/* 
  * 这个东西到底我们封装成什么?
    * 类
    * 对象
    * 函数  √
*/

// const baseURL = 'http://localhost:3000' // 本地启动
// const baseURL = 'http://10.31.154.189:3000' // 公司局域网启动
// const baseURL = 'http://10.31.154.110:3000' // 测试环境
// const baseURL = 'http://10.31.154.456:3000' // 上线环境
import axios from 'axios'
import { Toast } from 'vant'
import Vue from 'vue'
Vue.use( Toast )
const instance = axios.create({  // 创建一个axios实例
  // baseURL, 
  timeout: 5000,
});

// 默认表单提交
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';


// 添加请求拦截器
instance.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  // 如果你没有登录,项目中任何页面你都进不去-后台管理系统

      // 自定义加载图标
    Toast.loading({
      message: '加载中...',
      forbidClick: true,
      loadingType: 'spinner'
    });

  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});

  // 添加响应拦截器
  instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么

    Toast.clear()

    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

const request = ({
  url,
  method = "GET",
  params,
  data, 
  withCredentials = false, // default
  headers
}) => {
  return new Promise(( resolved,rejected ) => {
    // 区别两个不同的数据请求就行  get  post 
    switch ( method.toUpperCase() ) {
      case 'POST':
        var real_data = {}
        if ( headers['Content-Type'] == 'application/x-www-form-urlencoded' ){
          // 表单提交
          const p = new URLSearchParams()
          for ( let key in data ) {
            p.append( key, data[ key ] )
          }
          real_data = p
        } else {
          // json提交
          real_data = data 
        }
          instance.post( url,data = real_data, {
            withCredentials, // default
            headers
          }).then( res => resolved( res ))
            .catch( err => rejected( err ))
        break;

        case 'PUT':
          instance.put( url, {
            method,
            params,
            withCredentials, // default
            headers
          }).then( res => resolved( res ))
            .catch( err => rejected( err ))
        break;
        default:
          instance.get( url, {
            method,
            params,
            withCredentials, // default
            headers
          }).then( res => resolved( res ))
            .catch( err => rejected( err ))
          break;
        }
    })
}
export default request 
// module.exports = request 

7.如何改webapp的图标和标题

在public/index.html中修改,另外还可以在改文件下使用font-awesome,使用组件

8.什么是1px适配

引入border.styl文件

border($border-width = 1px, $border-color = #ccc, $border-style = solid, $radius = 0)
  // 为边框位置提供定位参考
  position: relative;

  if $border-width == null
    $border-width: 0;

  border-radius: $radius;

  &::after
    // 用以解决边框layer遮盖内容
    pointer-events: none;
    position: absolute;
    z-index: 999;
    top: 0;
    left: 0;
    // fix当元素宽度出现小数时,边框可能显示不全的问题
    // overflow: hidden;
    content: "\0020";
    border-color: $border-color;
    border-style: $border-style;
    border-width: $border-width;
    
    // 适配dpr进行缩放
    @media (max--moz-device-pixel-ratio: 1.49), (-webkit-max-device-pixel-ratio: 1.49), (max-device-pixel-ratio: 1.49), (max-resolution: 143dpi), (max-resolution: 1.49dppx)
      width: 100%;
      height: 100%;
      if $radius != null {
        border-radius: $radius;
      }
    
    @media (min--moz-device-pixel-ratio: 1.5) and (max--moz-device-pixel-ratio: 2.49), (-webkit-min-device-pixel-ratio: 1.5) and (-webkit-max-device-pixel-ratio: 2.49),(min-device-pixel-ratio: 1.5) and (max-device-pixel-ratio: 2.49),(min-resolution: 144dpi) and (max-resolution: 239dpi),(min-resolution: 1.5dppx) and (max-resolution: 2.49dppx)
      width: 200%;
      height: 200%;
      transform: scale(.5)
      if $radius != null {
        border-radius: $radius * 2;
      }
    
    @media (min--moz-device-pixel-ratio: 2.5), (-webkit-min-device-pixel-ratio: 2.5),(min-device-pixel-ratio: 2.5), (min-resolution: 240dpi),(min-resolution: 2.5dppx)
      width: 300%;
      height: 300%;
      transform: scale(.33333)
      if $radius != null {
        border-radius: $radius * 3;
      }
    
    transform-origin: 0 0;

9.vue-router的使用(路由)

9.1 安装

$ npm i vue-router -S

9.2 引入所需模块,安装插件,创建路由表

// 1. 引入所需要模块
import Vue from 'vue'
import VueRouter from 'vue-router'
import routerTable from './routes'
// 2. 安装插件
Vue.use( VueRouter )

// // 3. 创建路由表(单独创建一个文件routes.js)
// const routerTable = []

// 4. 创建路由模块
// const router = new VueRouter( options )
const router = new VueRouter({
  mode: 'history',// 需要后端配置 
  routes: routerTable // 配置路由表
})
export default router 

9.3 在main.js中引入路由模块

// 引入路由模块
import router from '@/router'
new Vue({
  // router: router,
  router,// 为全局注入路由,我们会得到两个属性  $router  $route
  store,
  render: h => h(App),
}).$mount('#app')

9.4 二级路由

  • 先配置路由
{
    path: '/home',
    component: Home, // 路由路径对应渲染的组件
    children: [ // 子路由表
      // 一个对象就是一个子路由配置
      { 
        path: 'hot',// 子路由不加 /
        component: HotMovieComp,
        name: 'hot', // 给路由起了个名字
        meta: { // 元信息
          include: 'HotMovieComp'
        }
      }
      ]
 }
  • home组件页面内引入组件,注册组件,再使用组件
<!-- to是路由路径  tag渲染是什么就渲染什么标签 -->
    <!--写法一-->
      <!-- <router-link to = "/home/hot" tag = "li" active-class = "active"> 正在热映 </!-->
	<!--写法二 就是方便一些,注意to前加: -->
      <router-link :to = "{ name: 'hot' }" tag = "li" active-class = "active"> 正在热映 </router-link>
      <router-link :to = "{ name: 'coming' }"  tag = "li" active-class = "active"> 即将上映 </router-link>

9.5 meta的作用

这是定义的元信息,keep-alive 上有个include,可以隐藏执行后台的选项,就只显示被切换到的组件

 meta: { // 元信息
          include: 'HotMovieComp'
        }   

10.动态组件加载

使用vue提供的内置组件 router-view 来接收路由对一个的组件,外层套实现缓存,放后台缓存,缓存速度快

<keep-alive
      :include="$route.meta.include"
    >
      <router-view></router-view>
    </keep-alive>

11.Vue组件库配置

  • pc
    • element-ui
    • iview
  • 移动端
    • Mint-ui(https://mint-ui.github.io/#!/zh-cn)
    • Vant-ui(https://youzan.github.io/vant/#/zh-CN)
  • 安装(按需引入)按官方修改
$ npm i mint-ui -D/npm i vant -D
$ npm install babel-plugin-component -D/npm install babel-plugin-import -D

12.组件通信(重点)

13.动态路由的配置

通过在path后加:id

1.动态路由中的路由传参 - 路由接参

  • $route

2.编程式导航

  • $router
    • push vs replace
      • push会将我们操作放入历史记录,点击浏览器返回会一层一层返回
      • replace不会将我们的操作放入历史记录,点击浏览器返回反回2层

14.全局过滤器

  1. 在filters中定义方法
import Vue from 'vue'
Vue.filter('curreny',val => {
  return '¥ ' + val 
})
  1. 在main.js中导入import ‘@/filters’
    3. 在需要使用的地方加‘|curreny’(|是管道符)

15.在跳转详情页的时候tabbar要消失

对路由做判断,可以用watch进行监听

  watch: {
    $route: {
      deep: true,
      handler () {
        if ( this.$route.name == 'detail') {
          this.tabBarFlag = false 
        } else {
          this.tabBarFlag = true 
        }
      }
    }
  }

16.购物车逻辑功能的实现(重难点)

  • 在加购之前先要判断本地存储中是否有数据
    • 若有,判断是否是同一个商品
      • 若是,数量增加
      • 若不是,直接添加
    • 若没有,直接添加

1.封装一个storage.js

export const getStorage =  ( name ) => {
  return localStorage.getItem( name ) && JSON.parse(localStorage.getItem( name )) || []
}

export const saveStorage = ( name, value ) => {
  localStorage.setItem( name,JSON.stringify(value) )
}

2.在加购页面时,使用storage.js

addShopCar () {
        // 1. 获取数据  getStorage
        const data = getStorage('shopcar')  // [] || [{}]
        if ( data.length != 0 ) {
          // 有数据   判断是不是同一个商品
          const f = data.some( item => item.id == this.$route.params.id )
          if ( f ) {
            // true 同一个商品
            data.map( item => {
              if ( item .id == this.$route.params.id ) {
                item.num += this.num 
                return 
              }
            })
          } else {
            // false 不同商品
            data.push({
              ...this.$route.query,
              num: this.num 
            })
          }

        } else {
          // 没有数据
          // data.push(当前商品信息)
          data.push({
            ...this.$route.query,
            num: this.num 
          })
        }
        saveStorage('shopcar', data )
      }

17.导航守卫(别名路由钩子,路由守卫,路由拦截)

作用:对路由的跳转进行拦截

类型:

  • 1.全局导航守卫:对整个项目做控制
  • 2.路由独享守卫:对单个路由的路由配置做控制,写在路由表中
  • 3.组件内守卫:对组件对应的路由做控制

使用:

  • 1.全局导航守卫
    • 全局前置守卫( router.beforeEach(to,from,next))
    • 全局后置守卫( router.afterEach(to,from,next))
    • 全局更新守卫【 可忽略, 使用和前置守卫一样 】
      1. 区别: 是否完整遍历路由表
        1. 更新守卫要遍历完整路由表之后才跳转页面

使用场景:

  • 全局前置守卫:后台管理系统||社区app
router.beforeEach(( to,from,next ) => {
    console.log("lucia: to", to)
    console.log("lucia: from", from)
    // console.log("lucia: next", next)
    // next( false )
    // next() == next( true )
    // next( true )
    if ( to.path == '/home/hot' ) {
       next()
    }
    const token = getCookie(' _token')
    console.log('token',token)
    if ( token || to.path == '/login') {
       next()
    } else {
       next('/login')
    }

使用方法:
1.导航守卫参数 /home -> /category
1. from 表示当前路由 /home
2. to 表示目标路由 /category
3. next [必须要写的]
3.1. next表示两者之间的连接
3.2. 取值
3.2.1. next() //默认连通
3.2.2. next( true ) // 表示连通
3.2.3. next( false ) // 不表示断开连接
3.2.4. next(路由路径)
3.2.4.1. next(’/home’)
3.2.4.2. next({ name: ‘home’, params: {},query: {} })
3.2.5. next( vm => { } ) // vm指的是目标组件

  • 全局后置守卫:没有拦截这一功能,只有提示功能,参数只有to,from,功能同上
  • 2.路由独享守卫
    使用方法:在router/router.js中需要守卫的组件
  {
  path: '/shopcar',
  component: ShopCar,
  beforeEnter ( to,from,next ) {
    console.log('to',to)
    const token = getCookie('_token')
    if ( token ) {
      console.log('token')
      next()
    } else {
      Toast.fail('您还没有登录,无法查看购物车,请先去登录')
      next( false )
    }
  },
  meta: {
    include: 'ShopCar'
  }
}
  • 3.组件内守卫
    使用方法:
  1. 组件前置守卫【 钩子 】(beforeRouterEnter)
  2. 拦截组件的进入
  3. 执行: 创建创建前执行,这个时候没有组件,没有this
  4. 功能
    1. 判断是否有token,然后是否能进入当前页面
    2. 数据预载
      1. 进入组件前,提前得到数据,并将这个数据赋值给组件
  5. 组件后置守卫【 钩子 】(afterRouterEnter)
  6. 拦截组件离开
  7. 执行: 离开组件前,这个时候有组件,有this
  8. 组件更新守卫
  9. 专用于: 动态路由

18.创建一个cookie.js(utils/cookie.js)

export const getCookie = name => {
  var cookies = {};
  if(document.cookie){
      var objs = document.cookie.split(';');
      for(var i in objs){
          var index = objs[i].indexOf('=');
          var key = objs[i].substr(0,index);
          var value = objs[i].substr(index+1,objs[i].length);
          cookies[key] = value;
      }
  }
  return cookies[ name ];
}
export const setCookie = ( name, value, opts ) => {
   //opts: maxAge,path,domain,secure
   if(name && value){
    var cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
    if(opts){
        if(opts.maxAge){
            cookie += ';max-age=' + opts.maxAge;
        }
        if(opts.path){
            cookie += ';max-age=' + opts.path;
        }
        if(opts.domain){
            cookie += ';max-age=' + opts.doamin;
        }
        if(opts.secure){
            cookie += ';max-age=' + opts.secure;
        }
    }
        document.cookie = cookie;
        return cookie;
    }else{
        return '';
    }
}
export const  remove = key => {
  if(getCookie()[key]){
      document.cookie = key + '=;max-age=0';
  }
}
export const clear = () => {
  var cookies = getCookie();
  for(var i in cookies){
      document.cookie = cookies[i] + '=;max-age=0';
  }
}

19.vue中动画效果的实现

  1. 实现 -> animate.css css3动画效果
  2. 使用
    • 安装: yarn add animate.css /npm i animate.css -S

    • 现在main.js中导入animate.js

    • import 'animate.css'
      
    • 在动画组件/元素外层加一个 Vue 内置组件 transition

    • 在transition标签内写enter-active-class=“animated 进入动画类名” leave-active-class=“animated 离开动画类名”,还要加个mode属性:in-out(先进后出)/out-in(先出后进)

20. vuex(重点!!!)

1.什么是Vuex?

  • Vuex是vue的插件,它是用来实现多组件的状态共享
  • 什么是状态?
    • 我们用一条数据来控制一个视图,那么这个数据就称之为状态,这个管理模式我们称之为状态管理
  • 那么这个状态我们又应该如何去管理、存储呢? —Vuex

2.Vuex的好处

  • 1.项目中的数据集中管理,方便将来的维护和更新
  • 2.项目中的数据的使用,需要流程,vuex提供了这个流程
  • 3.它还可以分担MVVM中VM的逻辑功能

3.Vuex在什么场景下应该使用

  • 中大型项目用vuex更好
  • 数据交互频繁
  • 用户交互频繁

4.Vuex使用流程

  • 简易版使用【数据集中书写 -所有数据写在一个文件中】
  • 正式项目使用 【数据模块化管理[数据分片]】
    • 数据
      • home
      • category
      • user

5.Vuex的核心组成部分:
actions和mutations共同承担一部分vm的逻辑

  • 1.actions :动作(如点击之类事件操作)用于后端交互
  • 2.mutations :用于修改数据,更新视图 vuex调试工具主要调试的是mutations
  • 3.state :状态,数据
    流程:用户点击(发起一个动作)–dispath–>actions–commit–>mutations---->state---->用户

6.安装 yarn add vuex /npm i vuex -S

7.简易版vuex

  • 1.新建文件夹store/index.js,
  • 2.在main.js中全局注册,并为全局注入store
import store from '@/store'
new Vue({
  // router: router,
  router,// 为全局注入路由,我们会得到两个属性  $router  $route
  store,// 为全局注入store,我们会得到一个属性   $store
  render: h => h(App),
}).$mount('#app')
  • 3.在actions中定义方法,在组件页面触发actions中的方法(this.$store.dispath)
    actions定义的方法有两个参数(store,payload),store是store的实例,payload是负载,也就是组件视图传给我们的数据。在store的方法函数中定义action常量
// 1. 引入vuex
import Vuex from 'vuex'
import Vue from 'vue'
// 引入动作常量
import { INCREMENT,DECRMENT } from './actionType'
Vue.use( Vuex )

// 2. 创建store.js
// const store = new Vuex.Store( options )
const store = new Vuex.Store({
  state: {
    count: 0
  },
  actions: { 
    // 对象中存放的是创建动作的方法
    increment ( store,payload ) {
      // store就是store实例
      // payload  负载 就是组件视图传递给我们的数据
      // console.log(payload)
      // console.log('increment')
      // 创建动作
      const action = {
       type: INCREMENT,// type是一个类型,表示组件中完成了什么类型的动作 
       payload
      }
      // 在由store发送动作
      store.commit( action ) // 将action动作发给了mutations
    },
    decrement ({ commit }) {
      commit({
        type: DECRMENT
      })
    }
  },
  mutations: {
    // 对象中存放的是修改 state 的方法 
    [ INCREMENT ] ( state ,action) {
      // 第一个参数就是 state 
      // 第二个参数就是actions中发过来的action
      // 修改数据
      state.count += action.payload
      state.count ++ 
    },
    [ DECRMENT ] ( state ) {
      state.count --
    }
  },
  // getters
})
export default store  

8.项目中如何使用vuex(利用辅助工具)

  • 1.新建文件夹store/index.js,
  • 2.在main.js中全局注册,并为全局注入store
import store from '@/store'
new Vue({
  // router: router,
  router,// 为全局注入路由,我们会得到两个属性  $router  $route
  store,// 为全局注入store,我们会得到一个属性   $store
  render: h => h(App),
}).$mount('#app')
  • 3.创建home/store.js
/* 
  * home的vuex
  * 很多公司
    * actions直接不写  
*/

import request from '@/utils/request'
import api from '@/api'


// 常量定义
const GET_HOT_MOVIES = 'GET_HOT_MOVIES'
const GET_NEW_MOVIES = 'GET_NEW_MOVIES'

export default {
  state: {
    movies: {}
  },
  actions: {
    async getMovies ({ commit }) {
      // 发送数据请求
      const result = await request({
        url: api.home.getHotMovie,
        params: {
          token: '',
          optimus_uuid: 'F2C8CA50060111E9BE3B2FA6BBC8F42F783446B54C974221B87A48F0BB404BD5',
          optimus_risk_level: 71,
          optimus_code: 10
        }
      })

      commit({
        type: GET_HOT_MOVIES,
        payload: result.data 
      })

    },
    async getNewMovies ({ commit },id) {
      const result = await request({
        url: api.home.getComingMovie,
        params: {
          token: '',
          movieIds: id, 
          optimus_uuid: 'F2C8CA50060111E9BE3B2FA6BBC8F42F783446B54C974221B87A48F0BB404BD5',
          optimus_risk_level: 71,
          optimus_code: 10
        }
      })
      commit({
        type: GET_NEW_MOVIES,
        payload: result.data.coming
      })
    }
  
  },  
  mutations: {
    [ GET_HOT_MOVIES ] ( state,action ) {
      // 修改数据
      state.movies = action.payload
    },
    [ GET_NEW_MOVIES ] ( state,action ) {
      state.movies.movieList.push( ...action.payload )
    }
  } 
}

21.Betterscroll的使用(可以用于列表滚动)

1.保证布局正确()
2.安装:$yarn add better-scroll
3.找到组件引入并使用(https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/#better-scroll%20%E6%98%AF%E4%BB%80%E4%B9%88)

import BScroll from 'better-scroll'
    mounted () {
      // 发起数据请求
      this.getMovies()
      /* 以下代码实现的是 滚动 + 上拉加载 */
      const bs = new BScroll('.page',{
        click: true, // 开启页面可以点击
        pullUpLoad: {
          threshold: 50 // 离底部多少式触发
        }
      })

      let count = 0

      bs.on('pullingUp',() => {
        // 写的是上拉加载事件
        console.log('上拉')
        // 上拉一次,完成数据请求
        // this.getNewMovies( id )
        const ids = _.chunk( this.movies.movieIds.slice( 12 ), 10 )
        if ( count < ids.length ) {
          this.getNewMovies( ids[ count ].join(',') )
          bs.finishPullUp() // 结束上拉
        }
        if ( count == ids.length ) {
          console.log('到底了')
          bs.finishPullUp() // 结束上拉
          return;
        }
        count ++
      })

    }

22.loadsh的用法(是一个封装库)

1.安装: $yarn add loadsh
2.页面中引用

import _ from 'loadsh'

23.拦截器实现loading

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  // 如果你没有登录,项目中任何页面你都进不去-后台管理系统

      // 自定义加载图标
    Toast.loading({
      message: '加载中...',
      forbidClick: true,
      loadingType: 'spinner'
    });

  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});

  // 添加响应拦截器
  instance.interceptors.response.use(function (response) {
    // 对响应数据做点什么

注意事项

  • 如果加了scoped ,那么路径别名前加一个 ~

  • 运行项目: n p m r u n s e r v e / npm run serve / npmrunserve/yarn serve

  • 如果我们能把不同路由对应的组件分割成不同代码块,然后当路由被访问时才加载对应组件,这样就很高效。方法:结合Vue的异步组件和webpack的代码(注释语法)分割功能,实现路由的懒加载,效果如下,比如Home组件(routers.js)

    const Home = () => import(/* webpackChunkName: "group-lucia" */ '@/views/home/index.vue')
    
  • 激活属性(active-class)

  • 使用vue内置提供的 router-link 组件来完成tabbar的跳转

  <router-link 
            :to=" item.path "
            active-class = "active"
          >
            <i class="fas" :class = "[ item.iconName ]"></i>
            <span> {{ item.text }} </span>
  </router-link>

  • 如果数据存在渲染两次情况,其中一次时undefined/null,那么我们需要通过return this.data&& this.data.data // 处理方式判断来排除undefined/null
  • vue中对象的合并 Object.assign() -> Vue.set/this.$set( 属性,属性值 )
  • 变量加[ ]才会解析

你可能感兴趣的:(vue项目中的技术)