《web前端全栈成长计划》Vue第三章学习笔记(上)

举报
张辉 发表于 2020/09/08 09:57:24 2020/09/08
【摘要】 web前端全站成长计划第三阶段vue课程第三章的学习笔记

本文摘自 论坛 https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=71831&authorid=70062&page=1 笔者对vue学习的笔记。由于vue笔者也是刚刚接触,基本上都是以观看视频和具体动手实践的方式进行。为防止迷路,特收集整理成本博文。

文中的图片、代码很多来自于教程本身,但都来自于本人实践后截图和拷贝的结果,特此说明。


Vue 第三章 Vue路由

38 UI组件库 mint-ui

都是饿了吗出的

38.1 Mint UI

38.1.1 安装

npm install --save mint-ui

image.png

38.1.2 实现按需打包:

npm install --save-dev babel-plugin-component

image.png

配置.babelrc

"plugins": ["transform-vue-jsx", "transform-runtime",["component", [
  {
    "libraryName": "mint-ui",
    "style": true
  }
]]]

移动端需要引入fastclick,解决事件延迟问题,实现快速点击。

38.1.3 范例:

main.js引入mint

import {Button} from 'mint-ui'

// 注册成标签
// 以前在components中注册。
// 现在可以做全局注册 默认用mint预定好的名字
Vue.component(Button.name, Button)

App.vue定义button并使用:

<template>
 <mt-button type="primary" @click.native="handleClick" style="width:100%" >按钮</mt-button>
</template>

<script>
  import {Toast} from 'mint-ui'
  export default {
    methods: {
      handleClick () {
        Toast('Notice Message')
      }
    }

  }
</script>

38.1.4 实际效果:

image.png

大多数组件可以找到,解决很多实际的移动端UI开发问题。

具体需要开发者一一去尝试。

39 路由介绍

39.1 目标

image.png

39.2 分析:

SPA 单页应用

路由链接

点击路由链接,不向后台发请求,而是显示不同的路由组件。而不同的路由组件会在操作中向后台发请求。

路由插件:vue-router

39.3 下载并安装包:

npm install vue-router --save

image.png

39.4 概念:

路由器:管理路由。

什么是路由:是个映射关系。

后台路由 Key=Path,Value=(处理请求的回调函数)

前台路由 Key=Path , Value = 组件

在vueRouter里面暴露的是创建路由器的构造函数。

new VueRouter({

//

})

路由配置:数组,数组中的每个值都是对象

routes:[

{ //一般路由

    path: '/about',

    comonent: About

},

{ //自动跳转路由

    path: '/',

    redirect: '/about'

},

...

]

先需要配置路由器:

import router from './router'

new Vue({

    router

})

此后的路由才能访问

路由链接:

<router-link> 生成路由链接

<router-view> 显示当前路由组件

40 基本路由

40.1 目标

image.png

非路由组件放入components目录里

路由组件一般放入views或者pages目录

40.2 实践(具体步骤)

  1. 在views下定义好路由组件

  2. 在router的index.js中,将路由组件映射成路由

  3. 在某个(App.vue)组件中去写两种标签 router-link和router-view

选择了哪个,router-link-active就在哪个上面有。那么,只要给这个类名加样式,就可以把当前路由页面设置颜色。

views/About.vue

<template>
  <div>
    About
  </div>
</template>

<script>
export default {}
</script>

<style>

</style>

views/Home.vue

<template>
  <div>
    Home
  </div>
</template>

<script>
export default {}
</script>

<style>

</style>

router/index.js

/* 路由器模块 */
import Vue from 'vue'
import VueRouter from 'vue-router'

import About from '../views/About'
import Home from '../views/Home'

Vue.use(VueRouter)

// 默认暴露
export default new VueRouter({
  // 配置N个路由
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home
    },
    {
      path: '/',
      redirect: '/about'
    }
  ]
})

App.vue

<template>
  <div>
    <div class="row">
      <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header">
          Router Basic - 01         </div>
      </div>
    </div>

    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
          <router-link to="/about" class="list-group-item">About</router-link>
          <router-link to="/home" class="list-group-item">Home</router-link>
        </div>
      </div>


      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
            <router-view></router-view>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

  export default {
  }
</script>

<style>

</style>

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

import Vue from 'vue' /* 注意大小写 */
import App from './App'
import router from './router'

// 配置对象的属性都是固定的属性名,不能随便修改
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>',
  router // 路由器配置
})

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="stylesheet" href="./static/css/bootstrap.css">
    <title>vue_demo</title>
    <style>
      .router-link-active {
        color: red !important;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

40.3 演示效果:

image.png


40.4 配置优化:

liveActiveClass: 'active', //指定选中的路由链接的class

40.4 总结

编写路由三步:

  1. 定义路由组件

  2. 注册路由

  3. 使用路由 <router-link> <router-view>

41 嵌套路由

41.1 目标:

image.png

41.2 分析:

将上面简单路由的Home组件改为 News和Message两个组件。。

其中News下面是个数组,元素为单个文本。Message也是个数组,其元素是个对象{},有链接,有消息内容,还有消息id

41.3 实践(具体步骤)

在上例代码中修改:

views下新增News.vue

<template>
  <div>
    <ul>
      <li v-for="(news,index) in newsArr" :key="index">{{news}}    </ul>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        // 根据效果去设计数据结构
        newsArr: [
          'news001',
          'news002',
          'news003',
          'news004'
        ]
      }
    }
  }
</script>

<style>

</style>

views下新增Messages.vue

<template>
  <ul>
    <li v-for="(message, index) in messages" :key="message.id">
      <a href="??">{{message.title}}</a>
      </ul>
</template>

<script>
  export default {
    data () {
      return {
        // 根据效果去设计数据结构
        messages: [

        ]
      }
    },

    mounted () {
      // 模拟ajax请求从后台获取数据
      // 回调函数用箭头函数
      setTimeout(() => {
          const messages = [
            {
              id: 1,
              title: 'message001'
            },
            {
              id: 2,
              title: 'message002'
            },
            {
              id: 4,
              title: 'message004'
            }
          ]
          this.messages = messages
      }, 1000)
    }
  }
</script>

<style>

</style>

更新路由配置 router/index.js

/* 路由器模块 */
import Vue from 'vue'
import VueRouter from 'vue-router'

import About from '../views/About'
import Home from '../views/Home'
import News from '../views/News'
import Message from '../views/Message'

Vue.use(VueRouter)

// 默认暴露
export default new VueRouter({
  // 配置N个路由
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home,
      children: [
        {
          path: '/home/news',
          component: News
        },
        { // 简化写法,相对于home
          path: 'message',
          component: Message
        },
        {
          // 定义home的缺省页面
          path: '',
          redirect: '/home/news'
        }

      ]
    },
    {
      path: '/',
      redirect: '/about'
    }
  ]
})

41.4 演示效果:

image.png

点击Message后:

image.png

42 缓存路由

42.1 目标:

切换走了,再切换回来,希望数据还在。

42.2 分析:

现在不在了:说明当前About是新的。如果要求数据还在,就必须是个老的。

旧的路由组件啥时死了?——被切换时。

再切换回来时,重新创建。

43.3 做法:

增加keep-alive标签

43.4 应用场景:

很广泛,主要是不同的tab页有很多输入项,切换后,原来的输入项要保留。

但是,如果数据实时要求性高,要反复从后台读取数据时,应不做缓存

43.5 实现:

App.vue给route-view标签增加以下处理

<keep-alive>
  <router-view msg="abc"></router-view>
</keep-alive>

43.6 演示效果:

about输入值:

image.png

切换到其他地方:

image.png

再切换回来:

image.png

可以发现,刚才录入的数据还在。

43 向路由组件传递数据

43.1 目标:

image.png

点击上面的message01 ,弹出下面的内容

43.2 分析:

  1. 新增MessageDetail 页面

  2. 将MessageDetail映射成组件

  3. $route代表当前路由

image.png

$route.params.id

43.3 实践:

43.3.1 向路由组件传递数据:路径携带参数params。(方式1)

views/Message.vue

<template>
  <div>
    <ul>
      <li v-for="(message, index) in messages" :key="message.id">
        <!--<a href="??">{{message.title}}</a>

        ES5的语法,使用单引号‘
        ES6的语法:使用反单引号`
        -->
        <router-link :to="`/home/message/detail/${message.id}`">{{message.title}}</router-link>
          </ul>
    <hr>
    <router-view></router-view>
  </div>

</template>

<script>
  // 请求参数两种:
  // Param参数 ?
  // Query参数

  export default {
    data () {
      return {
        // 根据效果去设计数据结构
        messages: [

        ]
      }
    },

    mounted () {
      // 模拟ajax请求从后台获取数据
      // 回调函数用箭头函数
      setTimeout(() => {
          const messages = [
            {
              id: 1,
              title: 'message001'
            },
            {
              id: 2,
              title: 'message002'
            },
            {
              id: 4,
              title: 'message004'
            }
          ]
          this.messages = messages
      }, 1000)
    }
  }
</script>

<style>

</style>

views/MessageDetail.vue

<template>
  <div>
    ID:{{$route.params.id}}    <ul>
      id:  {{messageDetail.id}}       title: {{messageDetail.title}}       content: {{messageDetail.content}}     </ul>
  </div>
</template>

<script>

  export default {
    data () {
      return {
        messageDetail: {}
      }
    },

    mounted () {
      setTimeout( () => {
        const allMessageDetails = [
          {
            id: 1,
            title: 'message001',
            content: 'message001 content...'
          },
          {
            id: 2,
            title: 'message002',
            content: 'message002 content...'
          },
          {
            id: 3,
            title: 'message003',
            content: 'message003 content...'
          },
          {
            id: 4,
            title: 'message004',
            content: 'message004 content...'
          }
        ]
        this.allMessageDetails = allMessageDetails
        // 过滤产生的数据还是数组
        // 乘以1表示id为数字
        const id = this.$route.params.id * 1
        this.messageDetail = allMessageDetails.find(detail => detail.id === id)
      },1000)
    },

    //需要监视
    watch: {
      $route: function (value) { // 路由路径(param)发生了改变
        const id = value.params.id * 1
        this.messageDetail = this.allMessageDetails.find(detail => detail.id === id)
      }
    }
  }
</script>

<style>

</style>

router/index.js

/* 路由器模块 */
import Vue from 'vue'
import VueRouter from 'vue-router'

import About from '../views/About'
import Home from '../views/Home'
import News from '../views/News'
import Message from '../views/Message'
import MessageDetail from '../views/MessageDetail'

Vue.use(VueRouter)

// 默认暴露
export default new VueRouter({
  // 配置N个路由
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home,
      children: [
        {
          path: '/home/news',
          component: News
        },
        { // 简化写法,相对于home
          path: 'message',
          component: Message,
          children: [
            {
              path: '/home/message/detail/:id',  // 使用占位语法
              component: MessageDetail
            }
          ]
        },
        {
          // 定义home的缺省页面
          path: '',
          redirect: '/home/news'
        }

      ]
    },
    {
      path: '/',
      redirect: '/about'
    }
  ]
})

实际效果:

image.png

image.png


43.3.2 向路由组件传递数据:query参数(方式2)。

修改方式:

router/index.js 去掉id

children: [
  {
    path: '/home/message/detail',  // 使用占位语法
    component: MessageDetail
  }
]

views/Message.vue 将to改为 ?id=...

<template>
  <div>
    <ul>
      <li v-for="(message, index) in messages" :key="message.id">
        <!--<a href="??">{{message.title}}</a>

        ES5的语法,使用单引号‘
        ES6的语法:使用反单引号`
        -->
        <router-link :to="`/home/message/detail?id=${message.id}`">{{message.title}}</router-link>
          </ul>
    <hr>
    <router-view></router-view>
  </div>

</template>

views/MessageDetail.vue 将原来的params.id 改为 query.id

<template>
  <div>
    ID:{{$route.query.id}}    <ul>
      id:  {{messageDetail.id}}       title: {{messageDetail.title}}       content: {{messageDetail.content}}     </ul>
  </div>
</template>

<script>

  export default {
    data () {
      return {
        messageDetail: {}
      }
    },

    mounted () {
      setTimeout( () => {
        const allMessageDetails = [
          {
            id: 1,
            title: 'message001',
            content: 'message001 content...'
          },
          {
            id: 2,
            title: 'message002',
            content: 'message002 content...'
          },
          {
            id: 3,
            title: 'message003',
            content: 'message003 content...'
          },
          {
            id: 4,
            title: 'message004',
            content: 'message004 content...'
          }
        ]
        this.allMessageDetails = allMessageDetails
        // 过滤产生的数据还是数组
        // 乘以1表示id为数字
        const id = this.$route.query.id * 1
        this.messageDetail = allMessageDetails.find(detail => detail.id === id)
      },1000)
    },

    //需要监视
    watch: {
      $route: function (value) { // 路由路径(param)发生了改变
        const id = value.query.id * 1
        this.messageDetail = this.allMessageDetails.find(detail => detail.id === id)
      }
    }
  }
</script>

<style>

</style>

实际效果:

image.png

跟原来一致。

43.3.3 向路由组件传递数据:route-view属性携带数据(方式3)。

<route-view :msg="msg"><route-view>

其实用法跟props类似

组件通过特定的标签route-view来显示的。

如果App.cue想向Home.vue和About.vue传递数据。可以在router-view传。

App.vue

<router-view msg="abc"></router-view>

About.vue

  1. 在export中声明从App引入的属性

  2. 在模板中引用该msg

<template>
  <div>
    About
    {{msg}}    <input type="text">
  </div>
</template>

<script>
  export default {
    // 需要从App接收msg属性,先要声明
    props: {
      msg: String
    }
  }
</script>

<style>

</style>

实际效果:

image.png

可见msg已被传输到About


44 编程式路由导航

44.1 概念

什么叫做编程式?

从A页面跳转到B页面有两种做法:

  1. <a>标签,直接跳转

  2. 加监听,通过js的方式实现页面跳转


编程式路由导航:通过js代码实现路由的跳转

44.2 目标:

image.png

44.3 实践1:

App.vue

<template>
  <div>
    <div class="row">
      <div class="col-xs-offset-2 col-xs-8">
        <div class="page-header">
          Router Basic - 01         </div>
      </div>
    </div>

    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
          <router-link to="/about" class="list-group-item">About</router-link>
          <router-link to="/home" class="list-group-item">Home</router-link>
        </div>
      </div>

      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
            <keep-alive>
              <router-view msg="abc"></router-view>
            </keep-alive>

          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>

  export default {
  }
</script>

<style>

</style>

views/Message.vue

<template>
  <div>
    <ul>
      <li v-for="(message, index) in messages" :key="message.id">
        <!--<a href="??">{{message.title}}</a>

        ES5的语法,使用单引号‘
        ES6的语法:使用反单引号`
        -->

        <router-link :to="`/home/message/detail/${message.id}`">{{message.title}}</router-link>
        <button @click="pushShow(message.id)">push查看</button>
        <button @click="replaceShow(message.id)">replace查看</button>
          </ul>
    <hr>
    <router-view></router-view>
  </div>

</template>

<script>
  // 请求参数两种:
  // Param参数 ?
  // Query参数

  export default {
    data () {
      return {
        // 根据效果去设计数据结构
        messages: [

        ]
      }
    },

    mounted () {
      // 模拟ajax请求从后台获取数据
      // 回调函数用箭头函数
      setTimeout(() => {
          const messages = [
            {
              id: 1,
              title: 'message001'
            },
            {
              id: 2,
              title: 'message002'
            },
            {
              id: 4,
              title: 'message004'
            }
          ]
          this.messages = messages
      }, 1000)
    },

    methods: {
      pushShow (id) {
        this.$router.push(`/home/message/detail/${id}`)
      },

      replaceShow (id) {
        this.$router.replace(`/home/message/detail/${id}`)
      }
    }
  }
</script>

<style>

</style>

views/MessageDetail.vue

<template>
  <div>
    ID:{{$route.params.id}}    <ul>
      id:  {{messageDetail.id}}       title: {{messageDetail.title}}       content: {{messageDetail.content}}     </ul>
  </div>
</template>

<script>

export default {
  data () {
    return {
      messageDetail: {}
    }
  },

  mounted () {
    setTimeout( () => {
      const allMessageDetails = [
        {
          id: 1,
          title: 'message001',
          content: 'message001 content...'
        },
        {
          id: 2,
          title: 'message002',
          content: 'message002 content...'
        },
        {
          id: 3,
          title: 'message003',
          content: 'message003 content...'
        },
        {
          id: 4,
          title: 'message004',
          content: 'message004 content...'
        }
      ]
      this.allMessageDetails = allMessageDetails
      // 过滤产生的数据还是数组
      // 乘以1表示id为数字
      const id = this.$route.params.id * 1
      this.messageDetail = allMessageDetails.find(detail => detail.id === id)
    },1000)
  },

  //需要监视
  watch: {
    $route: function (value) { // 路由路径(param)发生了改变
      const id = value.params.id * 1
      this.messageDetail = this.allMessageDetails.find(detail => detail.id === id)
    }
  }
}
</script>

<style>

</style>


比较下push和replace的差异

push

  1. 先访问news

  2. 再访问message

  3. push detail 1

  4. 点击back--》应看到message

replace

  1. 先访问news

  2. 再访问message

  3. replace detail 1

  4. 点击back=》应看到news


实际效果:

image.png


因点击的过程太多,不便演示。暂时截个主图。效果其实跟前面提到的是一致的。

44.3 实践2:

目标及处理:

通过编码的方式也要实现回退

Message.vue增加以下内容:

<button @click="$router.back()">回退</button>

效果如下:

image.png

这种场景经常见到。

44.4 总结:

$router.push(path) 点击路由链接(可以返回)

$router.replace(path) 新路由替换老路由(不可以返回)

$router.go(-1) 后退 等同于 $router.back()

$router.go(1) 前进

注意 $route和$router的区别


源码分析章节略(感觉一来时间进度跟不上,二来难度大。)


(全文完,谢谢阅读)

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。