vue_travel项目知识整理

vue stylus 安装

$ npm install stylus --save
$ npm install stylus-loader --save
Stylus是一个CSS预处理器。那么在SaaS,Less和Stylus中,为什么选择后者呢?
因为Stylus是来源于Node.js社区,与js关系密切,所以基于Vue.js的开发,我们选择使用Stylus。
[详情查看](https://stylus.bootcss.com/)

vue 全局引入外部css文件

main.js 使用 import 导入外部css文件
import './assets/styles/reset.css'

vue css使用

组件内部css中引入其他css时,import需要加上@,路径需要加上~, 
  - @import '~../../../assest/styles/reset.css'
css样式穿透, scoped只修饰当前组件,使用插件渲染的组件需要使用样式穿透 >>> 

vue iconfont使用

// 下载iconfont项目,将字体文件以及css样式拷贝到项目中
// 引入全局iconfont样式,main.js下
import '@/assets/styles/iconfont.css'
// 组件内使用iconfont,标签必须添加iconfont样式,还有相对应图标的样式
<i class="iconfont iconhanhui"></i>

vue 路径优化之resolve的使用

// 当子组件引用一些公共组件或其他样式时,通常都会一长串的路径
import CommonGallery from '../../../common/gallery/Gallery'
@import '~../../../assets/styles/variables.styl'
这时配置build/webpack.bas.conf.js,resolve配置项alias属性
resolve: {
  // 表示引用组件是可以省略后缀名
  extensions: ['.js', '.vue', '.json'],
  alias: {
    'vue$': 'vue/dist/vue.esm.js',
    '@': resolve('src'),
    '$styles': resolve('src/assets/styles'),
    '$common': resolve('src/common')
  }
},
配置后就可以使用“别名”来引用相关组件
import CommonComponent from '$common/gallery/Gallery'
@import '~$styles/variables.styl'
// 这是webpack打包工具提供的方法

vue 移动端点击300毫秒延迟

fastclick常用于消除移动端点击事件触发的300ms延迟
// fastclick 安装使用
$ npm install fastclick --save
// main.js调用方法
import fastClickAttach from 'fastclick'
fastClickAttach.attach(document.body)

vue 使用 vue-awesome-swiper

// 安装:$ npm install swiper vue-awesome-swiper --save // => 基于swiper封装所以也要安装swiper插件
// 详情https://www.npmjs.com/package/vue-awesome-swiper
// vue-awesome-swiper基于swiper,[详情配置查看](https://www.swiper.com.cn/api/index.html)
// vue全局引用vue-awesome-swiper, main.js下:
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
// 引入swiper样式
import 'swiper/css/swiper.css'
Vue.use(VueAwesomeSwiper, /* { default options with global component } */)
// 组件结构
<template>
  <swiper :options="swiperOptions">
    <swiper-slide>
      <img />
      .....
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
    .....
  </swiper>
</template>
<script>
  export default {
    data () {
      return {
        // swiper组件的常用配置项
        swiperOptions: {
          // 设置初始化显示下标为2的slide,默认值0
          initialSlide: 2,
          // Slides的滑动方向,可设置水平(horizontal)或垂直(vertical),默认水平
          direction : 'vertical',
          // 切换速度,即slider自动滑动开始到结束的时间(单位ms),默认300
          speed: 300,
          // 设置为true 则开启loop模式,默认false
          // 会在原本slide前后复制若干个slide(默认一个)并在合适的时候切换,让Swiper看起来是循环的
          loop: true,
          // 启动动态检查器(OB/观众/观看者),当改变swiper的样式(例如隐藏/显示)或者修改swiper的子元素时,自动初始化swiper,默认false
          observer: true
          // 将observe应用于Swiper的父元素。当Swiper的父元素变化时,例如window.resize,Swiper更新。默认false
          observeParents: true,
          // 设置为true启动自动切换,并使用默认的切换设置。默认false
          autoplay: true,
          // 自动切换的时间间隔,单位ms
          autoplay: {
            delay: 1000, // 1秒切换一次, 存在此属性默认表示自动切换,和autopalay:true二选一
          },
          // pagination,使用分页器导航。分页器可使用小圆点样式(默认)、分式样式或进度条样式。
          pagination: {
            el: '.swiper-pagination', // 选择分页器的元素
            type: 'bullets',  // ‘bullets’  圆点(默认)‘fraction’  分式 ‘progressbar’  进度条‘custom’ 自定义
          },
          // 使用前进后退按钮来控制Swiper切换。
          navigation: {
            nextEl: '.swiper-button-next', // 选择前进按钮的元素
            prevEl: '.swiper-button-prev', // 选择后退按钮的元素
          },
        }
      }
    }
  }
</script>

vue 移动端+swiper多页图标渲染

一些app都有可以滑动的图标区域,假如一页只能显示8个图标,现在获取到数据一共有10个或多条数据
怎么渲染出根据数据来渲染几页的图标呢,核心思想就是一个二维数组
// 模拟获取到的图标数据
cosnt iconArr = ['icon1', 'icon2', 'icon3', 'icon4', 'icon5', 'icon6', 'icon7', 'icon8', 'icon9', 'icon10']
// 创建一个空数组,用来存储当前是第几页的图标
let pages = []
iconArr.forEach((item, index) => {      // 遍历数据
   const page = Math.floor(index / 8)   // 表示一页只能显示8个图标
   if (!pages[page]) pages[page] = []   // 如果当前这一页不存在的话,就创建当前页
   pages[page].push(item)               // 最后把当前页的数据添加在当前页
})
return pages
// vue组件渲染
<template>
  <swiper :options="swiperOptions" v-for="(page, index) of pages">
    <swiper-slide v-for="(item, index) of page">
      <span class="swiper-icon">{{ item }}</span>
    </swiper-slide>
    <div class="swiper-pagination" slot="pagination"></div>.
  </swiper>
</template>

vue 使用路由

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌
- 安装
  1. vue项目创建时选择使用路由,项目将自动在根实例中注册 router 选项,
     该 router 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$router 访问到
     src/router/index.js  // 自动配置根路由,
  2. 假设vue项目创建没有选择使用路由,手动将路由注册到根实例中
     - $ npm install vue-router --save
     - 手动创建目录 src/router/index.js
- 使用路由(项目初始化选择使用路由后将自动生成下列代码)
  import Vue from 'vue'
  import Router from 'vue-router'
  import Home from '@pages/home/Home'
  Vue.use(Router)
  export default new Router({
    routes: [{
     path: '/',
     name: 'Home',
     component: Home
    }]
  })
- 注册到根实例 // main.js
  import router from './router'
  new Vue({
    el: '#app',
    router,
    components: { App },
    template: '<App/>'
  })

vue 路由请求转发

vue开发的过程中可能存在一个问题,前端的请求地址的端口与后端是不一致,所以我们在前端的请求并不会被转发到后端上去
这也不是真正的跨域问题,因为当我们发布项目的时候会将前端代码打包放到后端去。这里我们就可以在前端通过配置一个请求转发来解决这样的问题
// config/index.js
proxyTable: {
  '/': {
    target: 'http://localhost:7001', // 假如是egg搭建的后端服务器,egg默认端口7001
    pathRewrite: {
      '/': ''
    }
  }
},
// 这样前端所有请求/开头的请求转发到7001的端口上去,修改配置后,重启项目才会生效

vue 动态路由配置

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件,
我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。
// router/index.js
import User from '@pages/user/User'
routes: [{
  path: '/user/:id',
  name: 'User',
  component: User
}]
子组件可以通过this.$router.params.id获取动态id

vue 嵌套路由

// router/index.js
routes: [{ 
  path: '/user/:id', 
  component: User,
  children: [{
    // 当 /user/:id/profile 匹配成功,
    // UserProfile 会被渲染在 User 组件的 <router-view> 中
    path: 'profile',
    component: UserProfile
  }, {
    // 当 /user/:id/posts 匹配成功
    // UserPosts 会被渲染在 User 组件的 <router-view> 中
    path: 'posts',
    component: UserPosts
  }]
}]

vue 编程式导航$router

除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法
在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push()
当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)。
this.$router.push(), 该方法的参数可以是一个字符串路径,或者一个描述地址的对象[参数详解查看](https://router.vuejs.org/zh/guide/essentials/navigation.html)

router.replace跟router.push很像,唯一不同的是,replace不会像history添加新纪录,也就是没有后退功能

vue 命名路由

在配置路由的时候可以通过一个标识让一个路由显得更方便一些
// router/index.js
routes: [{
  path: '/user/:userId',
  name: 'user',
  component: User
}]
// 子组件使用
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
等价于 this.$router.push({ name: 'user', params: { userId: 123 }})

vue 路由模式

vue-router 默认hash模式——使用URL的hash来模拟一个完整的URL,于是当URL改变时,页面不会重新加载。
hash模式会自动在url地址末尾加上#/
如果不想要很丑的hash,我们可以用路由的history模式,这种模式充分利用history.pushStateAPI来完成URL跳转而无须重新加载页面。
history模式打包问题,........
vue默认跳转router-link使用a标签渲染,当我们不想使用a标签渲染时,又想使用跳转功能
可以使用tag属性,来代替a标签渲染,例如:
<ul>
  // 页面最终会以li标签渲染,也有路由跳转功能
  <router-link tag="li" to="/">列表1</router-link>
</ul>

vue 路由配置 scrollBehavior

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。
当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:
// router/index.js
scrollBehavior (to, from, savedPosition) {
  return { x: 0, y: 0 } // 表示路由跳转一个新页面时,页面第一次加载滚动条的为是x坐标0,y坐标0
}

vue 异步组件加载

// router 配置
routes: [{
  path: '/user',
  name: 'user',
  component: () => import('./my-async-component')
}]
// 全局组件配置
Vue.component('async-component', () => import('./my-async-component')))
// 局部组件配置
export default {
  // ....
  components: {
    'async-component': () => import('./my-async-component')
  }
}

vue 函数节流 提高性能

防抖和节流的目的都是为了减少不必要的计算,不浪费资源,只在适合的时候再进行触发计算。
1. 函数防抖
- 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时;
  典型的案例就是输入搜索:输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时。
- 实现原理, 基本思想就是设置一个定时器,在指定时间内执行代码清楚上一次的计时器,并设置另一个定时器,直到函数请求停止并超过时间间隔
- 使用场景, 文本框输入搜索(连续输入避免多次请求接口)
- 大致代码实现:
export default {
  dadta() {
    return {
      timer: ''
    }
  },
  watch: {
    inputValue () {
      if (this.timer) clearTimeout(this.timer)
      this.setTimeout(()=> {
        axios.get('/getData', { params:{ inputValue: this.inputValue } })
        .......
      }, 100)
    }
  }
}
2. 函数节流
- 规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效; 
  典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效
- 实现原理, 用时间戳来判断是否到了回调执行,记录上次的时间戳,每次mousemove时间执行回调,
  回调中判断当前时间戳到上次时间戳是否达到在规定时间段,如果是,执行回调函数,并更新时间戳
- 使用场景, resize,scroll,mousemove,touchmove,
- 代码大致实现:
export default {
  data () {
    return {
      timer: '',
      lastTime: ''
    }
  },
  methods: {
    // 假设移动触发了函数
    handleMousemove () {
      const nowTime = Date.now()
      const delay = 200
      if (this.lastTime && (nowTime - this.lastTime) <= delay) {
        if(this.timer) clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          this.lastTime = nowTime
          this.handleMove()
        }, delay)
      }else {
        this.lastTime = nowTime
        this.handleMove() // 第一次无需延时
      }
    },
    handleMove () {
      .......
    }
  }
}

vue better-scroll的使用

- better-scroll是解决移动端滚动的一种方案,核心是基于iscroll实现,还扩展了某些功能
- better-scroll是通过纯javascript实现的,意味着没有依赖项,是一个轻量级的javascript库
- install
  $ npm install better-scroll --save
- template结构,better-scroll应用于外部的warpper容器,滚动部分是content
  // 请注意:better-scroll指挥处理wrapper的第一个子元素(content),其他元素被忽略
  <template>
    <div class="wrapper" ref="wrapper">
    	<ul class="content">
    		<li>...</li>
    		<li>...</li>
    		<li>...</li>
    	</ul>
      // 放置一些其他内容,不会影响滚动  
    </div>
  </template>
- vue 组件中使用
  import BScroll from 'better-scroll'
  mounted () {
    this.scroll = new BScroll(this.refs.wrapper) // 参数接收一个DOM元素
  }
- 滚动的原理
  .wrapper容器,设置其高度固定,.content是父容器的第一个子元素,其高度随其内容的大小而增加
  当内容的高度不超过父容器的高度时,内容将不会滚动,一旦超过,就可以滚动内容

vue better-scroll模拟app选择城市页面

当手指在右边字母表中移动时,页面内容滑动到相对应的字母开头的城市
better-scroll提供一个原型上的方法: this.scroll.scrollToElement(el,time,offsetX,offsetY,easing)
el: 目标DOM元素。如果值是一个字符串,底层使用queryelector获取元素
time: 滚动到对应元素需要的动画时间, 单位毫秒
offsetX: x到目标元素的偏移量,如果值为true,则滚动到目标元素的中心。
offsetY: y到目标元素的偏移量,如果值为true,则滚动到目标元素的中心。
easing:  动画过渡的速度,linear,slow.....
this.scroll.scrollToElement(this.refs['A'])
[更多配置信息查看](https://better-scroll.github.io/docs/en-US/guide/base-scroll-api.html#properties)

vue touchEvent事件

touchstart  // 手指长按
touchmove   // 手指移动
touchend    // 手指松开
touchEvent.touches事件是一个touchList集合,使用下标[0] 可以获取手指到浏览器距离等信息

vue 列表渲染ref绑定返回一个数组

当列表渲染组件时绑定ref时,ref的时候返回的是一个数组
const data = ['one', 'two', 'three']
<ul>
  <li v-for="item in data" :ref="item">item</li>
</ul>
this.$refs.one // 返回的是一个数组, this.$refs.one[0]就能获取到相对应的DOM元素

vuex 使用

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。如果项目很小,可以不使用vuex
这个状态自管理应用包含以下几个部分:
  - state,驱动应用的数据源;
  - view,以声明方式将 state 映射到视图;
  - actions,响应在 view 上的用户输入导致的状态变化。
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
Vuex 和单纯的全局对象有以下两点不同:
  - Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  - 不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。
Vuex安装
  $ npm install vuex --save
在一个模块化的打包系统中,您必须显式地通过 Vue.use() 来安装 Vuex:
  // 创建一个仓库 src/store/index.js
  import Vue from 'vue'
  import Vuex from 'vuex'
  Vue.use(Vuex)
  export default new Vuex.Stroe({
    state: {
      count:'',
      ....
    },
    actions: {
      ....
    },
    mutations: {
      ...
    }
  })
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到
  // main.js
  import store from './store'
  new Vue({
    el: '#app',
    router,
    store,
    components: { App },
    template: '<App/>'
  })

vuex state

通过在根实例中注册store选项后,子组件可以通过this.$store.state.count访问到该状态

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。
为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,
import { mapState } from 'vuex'  // => 结构赋值,相当于mapState = vuex.mapState
注意: mapState名字不能随便取,因为随便取的话,vuex对象下没有这个方法
computed: {
  otherComputed () {/* do something... */},
  
  // 将this.count 映射为 this.$store.state.count
  // 将this.city 映射为 this.$store.state.city
  ...mapState(['count'], ['city']),    
  
  // 也可以接收一个对象, 
  // 将this.currentCount 映射为 this.$store.state.count
  // 将this.currentCity 映射为 this.$store.state.city
  // ...mapState({currentCount: 'count', currentCity: 'city'}),
}

vuex Mutations

更改 Vuex 的 store 中的状态(state)的唯一方法是提交 mutation。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
// store/index.js
export default new Vuex.Stroe({
  state: {
    count: 0,
  },
  actions: {
  },
  mutations: {
    increment (state, value) {
      state.count = value 
    },
    decrement (state, obj) {
      state.count = obj.count--
    }
  }
})
// 在组件中提交Mutations
  - 可以使用this.$store.commit('increment', 10)方法,第二个参数作为要改变的值,也可以是一个对象
  - 对象风格的提交方式, this.$store.commit({type: 'decrement', count: 10})
      type属性指定调用mutations对象的方法, 其他属性作为该方法的第二参数的属性

// 使用mapMutations辅助函数提交Mutations
import { mapMutations, mapState } from 'vuex' // 也可以同时引用
export default {,
  name: '',
  data () {// do something....},
  computed: {...mapState(['count'])},
  methods: {
    otherMethods () {// do something....},
    handleIncrementClick () {
      this.increment(this.count)
      this.incr(this.count)
    },
    handleDecrementClick () {
      this.decrement(this.count)
      this.decr(this.count)
    },
    // 将this.increment()映射为 this.$store.commit('increment')
    // 将this.decrement()映射为 this.$store.commit('decrement')
    ...mapMutations(['increment', 'decrement']),
    
    // 对象提交方式
    // 将this.incr()映射为 this.$store.commit('increment')
    // 将this.decr()映射为 this.$store.commit('decrement')
    ...mapMutations({incr: 'increment', decr: 'decrement'})
  }
}
// Vuex 的 store 中的状态是响应式的,当我们变更状态时,监视状态的 Vue 组件也会自动更新。
// Mutation 必须是同步函数,一条重要的原则就是要记住 mutation 必须是同步函数

vuex actions

// 在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。
Action 类似于 mutation,不同在于:
  - Action 提交的是 mutation,而不是直接变更状态。
  - Action 可以包含任意异步操作
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
因此你可以调用 context.commit 提交一个 mutation,
或者通过 context.state 和 context.getters 来获取 state 和 getters。
// store/index.js
export default new Vuex.Stroe({
  state: {
    count: 0,
  },
  actions: {
    increment (context) {
      context.commit('increment', context.count)
    },
    // 异步操作
    decrementAsync ({ commit }, obj) {
      setTimeout(() => {
        // 结构赋值, 这里的 commit === commit.commit 
        // 这里commit保存的是context上下文对象,而他有一个方法教commit,es6语法键值对都名字一样可以简写
        commit('decrement', obj)
      }, 1000);
    }
  },
  mutations: {
    increment (state, value) {
      state.count = value 
    },
    decrement (state, obj) {
      state.count = obj.count--
    }
  }
})
// 在组件中分发action
  - 可以使用this.$store.dispatch('increment')
  - 或者this.$store.dispatch('decrementAsync', {count: 10})
// 使用mapActions辅助函数
import { mapActions } from 'vuex'
export default {
  //....
  methods: {
    otherMethods () {/* do something... */},
    
    handleIncrementClick () {
      this.increment()
      this.incr()
    },
    handleDecrementAsyncClick () {
      this.decrementAsync({count: 10})
      this.decr({count: 10})
    },
    // 将 this.increment() 映射为 this.$store.dispatch('increment')
    // 将 this.decrementAsync() 映射为 this.$store.dispatch('decrementAsync')
    ...mapActions(['increment', 'decrementAsync']),
    
    // 对象提交方式
    // 将 this.incr() 映射为 this.$store.dispatch('increment')
    // 将 this.decr() 映射为 this.$store.dispatch('decrementAsync')
    ...mapActions({incr: 'increment', decr: 'decrementAsync'})
  }
}

vue 本地存储sessionStorage和localStorage

对浏览器来说,使用 Web Storage 存储键值对比存储 Cookie 方式更直观,而且容量更大,
它包含两种:localStorage 和 sessionStorage
  - sessionStorage(临时存储) :为每一个数据源维持一个存储区域,在浏览器打开期间存在,包括页面重新加载
  - localStorage(长期存储) :与 sessionStorage 一样,但是浏览器关闭后,数据依然会一直存在
// 使用方法
sessionStorage 和 localStorage 的用法基本一致,引用类型的值要转换成JSON
const info = { name: 'hou', age: 24, id: '001' }
const str ='hehe'
// 保存
sessionStorage.say = str
localStorage.setItem('say', JSON.stringify(info))
// 读取
sessionStorage.say // => hehe
localStorage.getItem('say')
// 删除
sessionStorage.removeItem('say') // 删除某个
localStorage.clear() // 删除全部

// 注意点
- localStorage有效期是永久的。一般的浏览器能存储的是5MB左右。sessionStorage api与localStorage相同。
- sessionStorage默认的有效期是浏览器的会话时间(也就是说标签页关闭后就消失了)。
- localStorage作用域是协议、主机名、端口。(理论上,不人为的删除,一直存在设备中)
- sessionStorage作用域是窗口、协议、主机名、端口。
- localStorage是window上的。所以不需要写this.localStorage,vue中如果写this,是指vue实例。会报错

vue keep-alive 组件

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。主要用于保留组件状态或避免重新渲染。
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中
当组件在 <keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
// 组件(标签)特性
  - include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
  - exclude - 字符串或正则表达式。只有名称匹配的组件都不会被缓存。
  - max - 数字。最多可以缓存多少组件实例。
// include 和 exclude 属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
<keep-alive include="a, b"></keep-alive>
<keep-alive include="/a|b/"></keep-alive>
<keep-alive include="['a', 'b']"></keep-alive>
// 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配
// max 最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉

// <keep-alive> 是用在其一个直属的子组件被开关的情形,<keep-alive> 要求同时只有一个子元素被渲染。

vue 递归组件

组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事
实现一个城市多级选择组件,加入有以下城市数据
const data = [{
  "code": "500000",
  "name": "重庆市",
  "list": [{
    "code": "500000",
    "name": "重庆市",
    "list": [{
      "code": "500101",
      "name": "沙坪坝区",
      "list": [{
        "code": "....",
        "name": "西永"
      }, {
        "code": "....",
        "name": "大学城"
      }]
    },{
      "code": "500102",
      "name": "九龙坡区"
    }]
  }]
}]
// city.vue
<template>
  <div class="wrapper">
    <div class="city" v-for="(item, index) of cities" :key="index">
      <div class="cityName">{{ item.name }}</div>
      <div v-if="item.list">
        <city :cities="item.list"></city>
      </div>
    </div>
    
  </div>
</template>
<sciprt>
  export default {
    name: 'city',
    props: {
      cities: Array
    },
  }
</sciprt>

vue 组件中export default的name属性作用

1. 在keep-alive组件中匹配
2. 递归组件时可以调用自身
3. 在页面使用dev-tools工具可以查看组件的名字就是name属性的值

vue 手机调试

babel-polyfill包,手机白屏(是手机不支持promise)
在手机端浏览, package.json/script/dev后面加上 --host 0.0.0.0
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 0.0.0.0",

打包上线

$ npm run build // => 会生成一个dist文件夹,给到后端
如果希望打包生成的文件最后在后端一个project目录运行代码
// config/index.js
assetsPublicPath: '/project'

猜你喜欢

转载自www.cnblogs.com/JunLan/p/12670313.html