VUE基础知识介绍(二)VUE提高

组件基础

什么是组件

**需求:**如果页面中有多个一样结构的控件,比如

<div id="app">
    
        <span>{
    {count1}}span> <button @click="changeCount1">按钮button> <br>
        <span>{
    {count2}}span> <button @click="changeCount2">按钮button> <br>
        <span>{
    {count3}}span> <button @click="changeCount3">按钮button> <br>
        <span>{
    {count4}}span> <button @click="changeCount4">按钮button> <br>
        <span>{
    {count5}}span> <button @click="changeCount5">按钮button> <br>
div>
<script src="./vue.js">script>
<script>
    new Vue({
      
        el: '#app',
        data: {
      
            count1: 0,
            count2: 0,
            count3: 0,
            count4: 0,
            count5: 0
        },
        methods: {
      
            changeCount1() {
      
                this.count1++;
            },
            changeCount2() {
      
                this.count2++;
            },
            changeCount3() {
      
                this.count3++;
            },
            changeCount4() {
      
                this.count4++;
            },
            changeCount5() {
      
                this.count5++;
            }
        }
    });
script>

问题:

  1. 代码重复 冗余
  2. 不利于维护

解决方案: 使用Vue中一个十分重要的特性-组件

体验组件的使用

<div id="app">
    
    <span-btn>span-btn>
    <span-btn>span-btn>
    <span-btn>span-btn>
    <span-btn>span-btn>
div>
<script src="./vue.js">script>
<script>
    // 注册全局组件
    Vue.component('span-btn', {
      
        template: `
{ {count}}
`
, data() { return { count: 0 } }, methods: { changeCount() { this.count++; } } }); new Vue({ el: '#app' });
script>

什么是组件:

组件系统是 Vue 的另一个重要概念,允许我们使用小型、独立和通常可复用的组件构建大型应用。

仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SyzLoUV-1597388161652)(./assets/1533888610958.png)]

  • 组件是可复用的 Vue 实例,且带有一个名字
  • 组件的选项:
    • 组件与 new Vue 接收相同的选项:例如 datacomputedwatchmethods 以及生命周期钩子等。
    • 仅有的例外是像 el 这样根实例特有的选项
  • 另外, 组件也有自己的选项 template components等

组件的特点

  • 组件是一种封装
  • 组件能够让我们复用已有的html、css、js
  • 可复用
  • 是一个特殊的Vue实例
  • 可以任意次数的复用
  • 每用一次组件,就会有一个它的新实例被创建
  • 组件中的data要求必须是一个函数,且需要返回一个对象
    • 组件有自己的作用域
  • template 每个组件模板有且只有一个根元素

建议: 在实际开发中,尽可能使用各种第三方组件

组件的分类和使用

  • **分类:**全局注册和局部注册
  • **使用(步骤)*1. 注册组件 2. 通过组件名字使用组件

全局注册

  1. 使用Vue.component(组件名,组件选项) 进行注册

    组件名:推荐小写加减号的命名方式

  2. 用在其被注册之后的任何 (通过 new Vue) 新创建的 (一个或者多个)Vue 实例

      Vue.component('组件名', {
     
            // 组件选项: data methods template等(没有el)
            // data 的值是一个函数, 需要返回一个对象
      });
<div id="app">
    
    <span-btn>span-btn>
    <span-btn>span-btn>
    <span-btn>span-btn>
    <span-btn>span-btn>
div>
<hr>
<div id="app1">
    <span-btn>span-btn>
    <My-Component>My-Component>
div>
<hr>
<div id="app2">
    <span-btn>span-btn>

div>
<hr>
<div id="app3">
    <span-btn>span-btn>
div>
<script src="./vue.js">script>
<script>
    // 1. 注册组件
    // Vue.component('组件名', {
      
    //     // 组件选项: data methods template等
    // });
    Vue.component('span-btn', {
      
        // template: 页面字符串,有且仅有一个根元素
        template: `
{ {count}}
`
, data() { return { count: 0 } }, methods: { changeCount() { this.count++; } } }); Vue.component('myComponent', { template: `

{ {num}}

`
, style: './style.css', data() { return { num: 0 } }, methods: { changeTitle() { this.num++; } } }); new Vue({ el: '#app' }); new Vue({ el: '#app1' }); new Vue({ el: '#app2' }); new Vue({ el: '#app3' });
script>

注意:

  1. 全局组件必须写在Vue实例创建之前,才在该根元素下面生效
  2. 在不同的Vue实例中可以使用多个不同的全局组件
  3. 每个组件有自己的作用域

局部注册

  • 直接在Vue实例里面通过 components选项进行注册
  • 对于 components 对象中的每个属性来说,
    • 其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Documenttitle>
    head>

    <body>
        <div id="app">
            
            <com-A>com-A>
            <com-B>com-B>
            <com-C>com-C>
        div>
        <script src="./vue.js">script>
        <script>
            // 局部组件的选项
            const comA = {
      
                template: `
{ {titleA}}
`
, data() { return { titleA: 'comA中的data里的titleA' } } }; const comB = { template: `
{ {titleB}}
`
, data() { return { titleB: 'comB中的data里的titleB' } } }; const comC = { template: `
{ {titleC}}
`
, data() { return { titleC: 'comC中的data里的titleC' } } }; new Vue({ el: '#app', // 1. 在Vue实例中设置components选项{组件名:组件选项} components: { // 在页面中的组件名:组件选项 'comA': comA, 'comB': comB, 'comC': comC } });
script> body> html>

组件嵌套

我们可以在new Vue()实例中使用自定义组件,

也可以在注册自定义组件时,嵌套另一个自定义组件,也就是父子组件的关系

父子组件-写法一

<div id="app">
    
    <parent-Com>parent-Com>
div>
<script src="./vue.js">script>
<script>
    // 1. 注册全局组件
    Vue.component('childCom', {
      
        template: `

childCom全局组件

`
}); Vue.component('parentCom', { // 在parentCom中嵌入childCom组件 // parentCom和childCom属于父子组件 // 父组件是parentCom // 子组件是childCom template: `

parentCom全局组件

`
}); new Vue({ el: '#app' });
script>

父子组件-写法二

<div id="app">
    
    <parent-Com>parent-Com>
div>
<script src="./vue.js">script>
<script>
    // 1. 局部组件的选项
    const childCom = {
      
        template: `

childCom局部组件

`
}; // 在parentCom组件选项中 使用components选项设置其子组件 // 在template中使用该子组件 const parentCom = { template: `

parentCom局部组件

`
, components: { 'childCom': childCom } }; new Vue({ el: '#app', components: { 'parentCom': parentCom } });
script>

组件通信

父->子(在子组件中使用父组件数据) props : 不可修改 单向数据传递

子->父(在父组件中使用子组件数据) 自定义事件!

兄弟组件

组件让我们提高了代码的复用性,接下来考虑如何在不同的组件中进行传值

比如: 父组件有items数组 在子组件中使用父组件中的items数组去渲染列表

父子组件通信

目的: 要在子组件中使用父组件中data中的属性值

关键点:通过Props给子组件传值

步骤:

  1. 在子组件中通过props声明自定义属性title
  2. 注册局部组件
  3. 使用子组件时,设置props选项, 通过自定义属性获取父组件的值
<div id="app">
    
    <component-a :title="msg" :lists="items">component-a>
div>

<script src="./vue.js">script>
<script>
    var ComponentA = {
      
        // 1. 在子组件中通过props声明自定义属性title
        template: `

{ { title }}

  • { {item.name}}
`
, // 用来接收外部传过来的数据 // 值的传递是单向的,内部不要修改props里变量的值 props: ['title', 'lists'] }; new Vue({ el: '#app', // 目的: 要在子组件中使用父组件的msg的值 data: { msg: 'hello heima', items: [{ 'id': 1, 'name': '小狗' }, { 'id': 2, 'name': '小猫' }, { 'id': 3, 'name': '小羊' } ] }, // 2. 注册局部组件 components: { 'component-a': ComponentA } });
script>

父子组件的传值有多种方法, 兄弟组件的通信也有自己的写法

避免混淆,这里我们先只讲父子组件通信的一种写法

会在后续的案例中会进行讲解

组件和模块

  • 模块:侧重于功能或者数据的封装
  • 组件:包含了 template、style 和 script,而它的 script 可以由各种模块组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sCzMZBz-1597388161657)(C:/Users/liu99/Desktop/temp/vue7%E5%A4%A9/01-vue/%E7%AC%94%E8%AE%B0/media/b25efd3e8af188b5ab36ccb66baddd71_hd.jpg)]

钩子函数

生命周期是指Vue实例或者组件从诞生到消亡经历的每一个阶段,在这些阶段的前后可以设置一些函数当做事件来调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-toQ1aHyA-1597388161723)(assets/lifecycle.png)]

<body>
  <div id="app">
    <h1>{
     {
     message}}</h1>
  </div>
</body>

<script>
  var vm = new Vue({
     
    el: '#app',
    data: {
     
      message: 'Vue的生命周期'
    },
    beforeCreate: function() {
     
      console.group('------beforeCreate创建前状态------');
      console.log("%c%s", "color:red" , "el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //undefined 
      console.log("%c%s", "color:red","message: " + this.message) 
    },
    created: function() {
     
      console.group('------created创建完毕状态------');
      console.log("%c%s", "color:red","el     : " + this.$el); //undefined
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化 
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化
    },
    beforeMount: function() {
     
      console.group('------beforeMount挂载前状态------');
      console.log("%c%s", "color:red","el     : " + (this.$el)); //已被初始化
      console.log(this.$el);
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化  
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化  
    },
    mounted: function() {
     
      console.group('------mounted 挂载结束状态------');
      console.log("%c%s", "color:red","el     : " + this.$el); //已被初始化
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); //已被初始化
      console.log("%c%s", "color:red","message: " + this.message); //已被初始化 
    },
    beforeUpdate: function () {
     
      console.group('beforeUpdate 更新前状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);   
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    updated: function () {
     
      console.group('updated 更新完成状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el); 
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    beforeDestroy: function () {
     
      console.group('beforeDestroy 销毁前状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);    
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message); 
    },
    destroyed: function () {
     
      console.group('destroyed 销毁完成状态===============》');
      console.log("%c%s", "color:red","el     : " + this.$el);
      console.log(this.$el);  
      console.log("%c%s", "color:red","data   : " + this.$data); 
      console.log("%c%s", "color:red","message: " + this.message)
    }
  })
</script>
</html>

前端路由

什么是单页应用

单页应用(single page web application,SPA),是在一个页面完成所有的业务功能,浏览器一开始会加载必需的HTML、CSS和JavaScript,之后所有的操作都在这张页面完成,这一切都由JavaScript来控制。

单页应用优缺点

  • 优点
    • 操作体验流畅
    • 完全的前端组件化
  • 缺点
    • 首次加载大量资源(可以只加载所需部分)
    • 对搜索引擎SEO不友好 -> 服务端渲染
    • 开发难度相对较高

单页应用的实现原理

前后端分离(后端专注于数据、前端专注于交互和可视化)+前端路由

  • Hash路由

    • 利用URL上的hash,当hash改变不会引起页面刷新,所以可以利用 hash 值来做单页面应用的路由,

      并且当 url 的 hash 发生变化的时候,可以触发相应 hashchange 回调函数。

    • 模拟实现:

    <a href="#/">首页</a>
    <a href="#/users">用户管理</a>
    <a href="#/rights">权限管理</a>
    <a href="#/goods">商品管理</a>
    <div id="box">
        </div>
    <script>
        var box = document.getElementById('box');
    window.onhashchange = function() {
           
        // #/users
        var hash = location.hash;
        hash = hash.replace('#', '');
        switch (hash) {
           
            case '/':
                box.innerHTML = '这是首页';
                break;
            case '/users':
                box.innerHTML = '这是用户管理';
                break;
            case '/rights':
                box.innerHTML = '这是权限管理';
                break;
        }
    };
    </script>
    
  • History路由

    • History 路由是基于 HTML5 规范,在 HTML5 规范中提供了 history.pushState || history.replaceState 来进行路由控制

vue-router

Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌

实现根据不同的请求地址 而显示不同的组件

快速体验

  1. 导入vue和vue-router

  2. 设置HTML中的内容

    
    <router-link to="/users">用户管理router-link>
    
    
    <router-view>router-view>
    
  3. 创建组件

    // 创建组件
    // 组件也可以放到单独的js文件中
    var Home = {
           
        template: '
    这是Home内容
    '
    }; var Users = { template: '
    这是用户管理内容
    '
    };
  4. 配置路由规则

    // 配置路由规则
    var router = new VueRouter({
           
        routes: [
            {
            name: 'home', path: '/', component: Home },
            {
            name: 'users', path: '/users', component: Users }
        ]
    });
    
  5. 设置vue的路由选项

    var vm = new Vue({
           
        el: '#app',
        router
    });
    

动态路由

场景: 不同的path对应同一个组件

注意: 变化的路由 改成 :参数

此时可以通过路由传参来实现,具体步骤如下:

  1. 路由规则中增加参数,在path最后增加 :id

    {
            name: 'users', path: '/users/:id', component: Users },
    
  2. 通过 传参,在路径上传入具体的值

    <router-link to="/users/120">用户管理router-link>
    
  3. 在组件内部可以使用,this.$route 获取当前路由对象

    var Users = {
           
        template: '
    这是用户管理内容 { { $route.params.id }}
    '
    , mounted() { console.log(this.$route.params.id); } };

路由嵌套

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q714WmOd-1597388161727)(./assets/1536283239126.png)]

如果存在组件嵌套,就需要提供多个视图容器

同时,router-link和router-view 都可以添加类名、设定样式

<div id="app">
    
    <nav>
        <router-link to="/top">热点router-link>
        <router-link to="/tech">教育router-link>
        <router-link to="/soc">社会router-link>
        <router-link to="/mus">音乐router-link>
        <router-link to="/te">体育router-link>
    nav>

    
    <router-view class="box">
    router-view>
div>

<script src="./vue.js">script>
<script src="./vue-router.js">script>
<script>
    // 组件:

    // 热点
    var Top = {
      
        template: '

Top

'
}; // 体育:带参数的二级路由 var Te = { template: `
  • 篮球
  • 足球
  • 好多球
`
}; // 教育:使用了data var Tech = { data: function() { return { name: "luck", age: 10, fn: function() { alert(1); } } }, template: `

{ {name}}

{ {age}}

`
} // 社会 var Soc = { template: '

soc

'
}; // 音乐:不带参数的二级路由 var Mus = { // template: '

mus

'
template: `
  • 流行
  • 古典
  • 摇滚
`
}; // 音乐:二级路由的视图 var Pop = { template: '

mus下的pop模块

'
}; // 体育:二级路由的视图 var Ball = { //路由参数 $route.params template: "

{ {$route.params}}

"
}; // 配置路由 var routes = [ // 热点 { path: '/top', component: Top }, // 教育 { path: '/tech', component: Tech }, // 社会 { path: '/soc', component: Soc }, { path: '/mus', component: Mus, //子路由配置 children: [{ path: 'pop', component: Pop, }] }, // 体育 { path: '/te', component: Te, children: [{ // /te/形参/10 path: ':cate/10', component: Ball }] }, //重定向:默认或者404界面 { path: '*', redirect: '/top' } ]; // 实例化路由 var router = new VueRouter({ // routes : routes routes }); // 实例化vue var vue = new Vue({ el: '#app', // router : router router });
script>

过渡和动画

基本用法就是给我们需要动画的标签外面嵌套transition标签 ,并且设置name属性

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

  • 在 CSS 过渡和动画中自动应用 class
  • 可以配合使用第三方 CSS 动画库,如 Animate.css

在 CSS 过渡和动画中自动应用 class

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

// v要替换成transition组件的name属性值
v-enter:定义进入过渡的开始状态。
v-enter-active:定义进入过渡生效时的状态。
v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。
v-leave: 定义离开过渡的开始状态。
v-leave-active:定义离开过渡生效时的状态。
v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。

示例:

<style>
    .box {
      
        position: absolute;
        left: 0;
        top: 50px;
        width: 100px;
        height: 100px;
        background-color: red;
    }
    .slide-enter, .slide-leave-to {
      
        left: 200px;
        opacity: 0;
    }
    .slide-enter-active, .slide-leave-active {
      
        transition: all 2s;
    }
    .slide-enter-to, .slide-leave {
      
        left: 0px;
        opacity: 1;
    }
style>
<button @click="isShow = !isShow">显示/隐藏button>

<transition name="slide"> 
    <div v-show="isShow" class="box">div>
transition>
<script>
    var vm = new Vue({
      
        el: '#app',
        data: {
      
            isShow: true
        }
    });
script>

自定义过渡动画的类名

可以通过transition组件自定义过渡动画的类名,可以方便结合第三方的动画库使用,比如:animate.css

// transition组件的属性 
enter-class
    enter-active-class
        enter-to-class (2.1.8+)
leave-class
    leave-active-class
        leave-to-class (2.1.8+)

示例:

<button @click="isShow = !isShow">togglebutton>
<transition 
            enter-active-class="animated fadeIn"
            leave-active-class="animated fadeOut">
    <div v-show="isShow">hellodiv>
transition>
<script>
    var vm = new Vue({
      
        el: '#app',
        data: {
      
            isShow: true
        }
    });
script>

vue-cli(脚手架)

为什么要用vue-cli

可以快速创建vue项目结构,而不需要我们一点点的去创建/管理项目所需要的各种文件夹/文件

什么是vue-cli

vue-cli是npm包

vue-cli 提供一个官方命令行工具,可用于快速搭建大型单页应用。

使用vue-cli

# 安装 Vue CLI 脚手架
# 如果已经安装过则不需要
# 这里安装的是最新版本 3版本
npm install -g @vue/cli

# 执行vue --verson查看是否安装成功,
# 显示vue的版本,就是安装成功了
vue -V

# 如果仍然要使用vue-cli 2版本的指令 需要安装一个桥接工具
npm install -g @vue/cli-init

# 使用脚手架工具初始化你的项目
# webpack-simple是一种工程模板
vue init webpack-simple 项目名称

# 进入你初始化好的项目
cd 项目路径

# 安装项目模板所需要的依赖
npm i

# 启动开发模式
# 或者 npm start
npm run dev

运行npm run dev后,会在浏览器中看到如下效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MofUzjp-1597388161730)(./assets/1534009067048.png)]

项目目录说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLL9nCag-1597388161732)(./assets/1534009729744.png)]

  • node_modules 项目依赖包
  • src 项目核心文件(项目核心代码都放在这个文件夹下)!!!
    • assets 静态资源(样式类文件,如css、less、sass以及外部的js文件)
    • App.vue 根组件,所有页面都是在App.vue下进行切换的
      • 也可以理解为所有的路由也是App.vue的子组件
    • main.js 入口文件:主要作用是初始化vue实例并使用需要的插件。
  • .babelrc babel配置参数
  • .editorconfig 代码格式
  • .gitignore git忽略文件
  • index.html 项目的首页
  • package-lock.json
  • package.json
  • README.md 项目说明
  • webpack.config.js webpack配置文件

注意:

一个vue页面通常由三部分组成:模板(template)、js(script)、样式(style)

我们关心的重点是src中的文件夹

单文件组件

说明:

  1. *.vue 文件,是一个自定义的文件类型,用类似HTML的语法描述一个Vue组件。
  2. 每个.vue文件包含三种类型的顶级语言块 ,

template 部分

  • 代表它的 html 结构
  • 必须在里面放置一个 html 标签来包裹所有的代码
  • 我们在其他地方写好了一个组件,然后就可以在当前template中引入

script 部分

export default {
     
    // 这里写你的代码,如
    el:,
    data:,
    props:
    // 省略
};

style 部分

就是针对我们的 template 里内容出现的 html 元素写一些样式

注意: vue-cli的作用就是让我们把精力放在业务编码上,一切准备的工作交给vue-cli去做

之后我们可以直接使用vue-cli去做案例或者项目

Vue案例

讲完了Vue基础知识和vue-cli工具

我们利用所讲知识完成一个简单的案例–英雄列表

目的:

  1. 熟悉vue-router的使用
  2. 熟悉单文件组件的使用
  3. 熟悉vue-cli的使用

案例演示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mqC1P2R-1597388161733)(./assets/1536664536268.png)]

功能拆分

  1. vue-cli创建项目hero
  2. 路由配置
  3. 英雄列表
    • 列表展示
    • 添加英雄
    • 编辑英雄
    • 删除英雄

项目起步

利用脚手架vue-cli生成项目结构

# 安装 Vue CLI 脚手架
# 如果已经安装过则不需要!
npm i -g @vue/cli

# 使用脚手架工具初始化你的项目
vue init webpack-simple 项目名称

# 进入你初始化好的项目
cd 项目路径

#安装项目所需依赖
npm i

# 启动开发模式
# 或者 npm start
npm run dev

调整模板

将vue-cli生成的文件中无用的代码进行删除

首页展示

步骤分析:

  1. 导入素材: 将课程包中index.html的标签结构放在App.vue的template中
  2. 安装[email protected]: index.html使用了bootstrap和index.css,在vue项目中安装和导入
  3. 在main.js中引入bootstrap和index.css
  4. 修改webpack配置: 程序报错、无法识别字体文件, 需要在webpack.config.js中进行配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrDDwDGO-1597388161734)(./assets/1534220243520.png)]

代码演示

1. 导入素材

2. 安装bootstrap,导入index.css

  1. npm i [email protected]
  2. 将课程包中的css文件夹放在assets中

3. 引入bootstrap和index.css

main.js

import Vue from 'vue'
import App from './App.vue'

import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";

new Vue({
     
    el: '#app',
    render: h => h(App)
})

4. 修改webpack.config.js配置

{
     
    test: /.(ttf|woff2|woff|eot)$/,
        loader: 'file-loader',
            options: {
     
                name: '[name].[ext]?[hash]'
            }
}

接下来我们用单文件组件的方式将页面文件提取为不同的组件

提取公共头部组件

步骤分析:

1. 新建AppHeader.vue

2. 修改App.vue的template

3. 使用AppHeader.vue

代码演示:

  1. 在src下新建components/AppHeader.vue
  2. 找到头部的标签结构,将其放置于AppHeader.vue的template中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vnrYJjq-1597388161735)(./assets/1534222080131.png)]

  1. 在App.vue中引入并使用AppHeader.vue组件
    1. 引入AppHeader.vue组件
    2. 注册AppHeader.vue组件
    3. 使用AppHeader.vue组件

AppHeader.vue

<template>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">CRUD</a>
</div>
</div>
</nav>
</template>

<script>
    export default {
     

}
</script>
<style>

</style>

App.vue

<template>
    <div>
    <!-- 3 使用AppHeader.vue组件 -->
<AppHeader></AppHeader>
<!--后面的标签结构 省略..-->
</div>
</template>

<script>

    // 1. 导入AppHeader.vue组件
    import AppHeader from './components/AppHeader';


export default {
     
    name: 'app',
    data () {
     
        return {
     

        }
    },
    // 2. 注册AppHeader组件
    components:{
     
        // 注意命名
        AppHeader:AppHeader
    }
}
</script>

<style lang="scss">

    </style>

提取侧边栏组件

步骤分析

1. 新建AppSilder.vue

2. 修改App.vue的template

3. 使用AppSilder.vue

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qS2Hm7UY-1597388161737)(./assets/1534223067628.png)]

提取英雄列表组件

新建AppList.vue,并将App.vue中的英雄列表的页面标签提取到AppList.vue中

步骤分析

1. 新建AppList.vue

2. 修改App.vue的template

3. 使用AppList.vue

Vue-Router使用

使用 Vue-Router 实现页面导航管理

步骤分析及代码演示

  1. 安装路由模块
npm i vue-router
  1. main.js 中加载
...
import VueRouter from 'vue-router' // 加载路由模块

// 注册到 Vue 中才可以使用
Vue.use(VueRouter)

// ...
  1. main.jsnewVueRouter 实例,并挂载到根实例的 router 选项中
// ...

// 配置路由表
const appRouter = new VueRouter({
     
    routes: [
    ]
})

// ...

new Vue({
     
    el: '#app',
    render: h => h(App),
    // 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
    router: appRouter
});
  1. 配置路由表
// ...
// 配置路由表
const appRouter = new VueRouter({
     
    // routes 选项用来配置路由表
    // 当请求 /xxx 的时候,渲染 xxx 组件
    // routes 是一个数组,数组中存储一些固定格式的对象
    // 对象 path 表示请求的路径
    // 对象的 component 用来指定当你请求 path 路径的时候,渲染该组件
    // 现在的问题是?匹配到 path 的时候,组件往哪里渲染?
    // 在你的根组件预留一个路由的出口,用来告诉路由到匹配到某个 path 的时候,把该组件渲染到哪里
    routes: [
        {
     
            path: '/foo',
            component: {
     
                template: `
foo 组件啊
`
} }, { path: '/bar', component: { template: `
bar 组件啊
`
} } ] }); // ...
  1. src/App.vue 组件中设置路由出口(告诉路由往哪里渲染 path 匹配到的组件)
<template>
    <div id="app">
        <AppHeader>AppHeader>
        <div class="container-fluid">
            <div class="row">
                <AppSidebar>AppSidebar>
                <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                    
                    
                    <router-view>router-view>
                div>
            div>
        div>
    div>
template>
...
  1. 在侧边栏 src/components/AppSidebar.vue 组件中 增加两个导航链接用来导航 foobar
<template>
    <div class="col-sm-3 col-md-2 sidebar">
        <ul class="nav nav-sidebar">
            <li class="active"><a href="#">英雄管理 <span class="sr-only">(current)span>a>li>
            <li><a href="#">用户管理a>li>
            <li><a href="#">商品管理a>li>
            <li><a href="#">订单管理a>li>
            
            <li><a href="#/foo">Go Fooa>li>
            <li><a href="#/bar">Go Bara>li>
        ul>
    div>
template>

<script>script>

<style>style>

将路由导航到 .vue 组件

src/components/Foo.vue:

<template>
    <div>
        Foo 组件
    div>
template>

<script>script>
<style>style>

src/components/Bar.vue:

<template>
    <div>
        Bar 组件
    div>
template>

<script>script>
<style>style>

src/main.js:

// ...
// ...
import Foo from './components/Foo'
import Bar from './components/Bar'
import HeroList from './components/HeroList'

// ...
// ...

// 配置路由表
const appRouter = new VueRouter({
     
    routes: [
        {
     
            path: '/foo',
            component: Foo
            // component: {
     
            //   template: `
foo 组件啊
`
// } }, { path: '/bar', component: Bar }, { path: '/heroes', component: HeroList } ] }); // ...

提取路由模块router.js

将main.js中路由相关的代码提取到router.js中

新建router.js

import Vue from 'vue';

// 1. 导入路由
import VueRouter from 'vue-router';

// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';


// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
     
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        {
      name: 'home', path: '/', redirect: {
      name: 'heroes' } },
        // 路由规则
        {
      name: 'heroes', path: '/heroes', component: AppList },
        {
      name: 'bar', path: '/bar', component: Bar },
        {
      name: 'foo', path: '/foo', component: Foo }
    ]
});

// 3 导出模块
export default router;

main.js

import Vue from 'vue'
import App from './App.vue'

// import Foo from './components/Foo'
// import Bar from './components/Bar'
// import AppList from './components/AppList'

// import VueRouter from 'vue-router' // 加载路由模块
// // 注册到 Vue 中才可以使用
// Vue.use(VueRouter);

// 1 导入路由对象
import router from './router';

import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";


new Vue({
     
    el: '#app',
    render: h => h(App),
    // 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
    // router: appRouter
    router
});

配置导航菜单

将AppSilder.vue中的a标签改成router-link

AppSilder.vue

<template>
    <div class="col-sm-3 col-md-2 sidebar">
        <ul class="nav nav-sidebar">
            <!-- <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
<li><a href="#/heroes">Reports</a></li>
    <li><a href="#">Analytics</a></li>
        <li><a href="#">Export</a></li>
            <li><a href="#/foo">Go Foo</a></li>
                <li><a href="#/bar">Go Bar</a></li> -->
                    <router-link tag="li" to="/heroes">
                        <a>英雄列表</a>
</router-link>
<router-link tag="li" to="/bar">
    <a>武器列表</a>
</router-link>
<router-link tag="li" to="/foo">
    <a>装备列表</a>
</router-link>
</ul>
</div>
</template>

<script>
    export default {
     

}
</script>
<style>

</style>

API-Server

接下来要实现具体的功能, 首先是英雄列表展示,其中的数据要来源于服务器

我们使用json-server快速启动api服务器 监听课程包中的db.json

可以使用postman测试接口

英雄列表数据渲染

利用axios发送请求获取英雄列表的数据渲染到AppList.vue的template中

步骤分析:

  1. 启动json-server
  2. 在安装并在AppList.vue中导入axios
  3. 在data选项中添加属性list:[]
  4. 将发送请求的方法写在methods中 loadData
  5. 在created钩子函数中调用loadData方法
  6. 将list中的数据渲染到template中的相应位置

代码演示:

AppList.vue

<template>
    <div>
        <h2 class="sub-header">Hero Listh2>
        <a class="btn btn-success" href="add.html">Adda>
        <div class="table-responsive">
            <table class="table table-striped">
                
                <thead>
                    <tr>
                        <th>#th>
                        <th>名称th>
                        <th>性别th>
                        <th>操作th>
                    tr>
                thead>
                <tbody>
                    <tr :key="item.id" v-for="(item, index) in list">
                        <td>{
    { index + 1 }}td>
                        <td>{
    { item.name }}td>
                        <td>{
    { item.gender }}td>
                        <td>

                            <a href="edit.html">edita>
                              
                            <a href="javascript:window.confirm('Are you sure?')">deletea>            td>
                    tr>
                tbody>
            table>
        div>
    div>
template>

<script>
    import axios from 'axios';

    export default {
      
        data(){
      
            return {
      
                list:[]
            }
        },
        created(){
      
            this.loadData();
        },
        methods:{
      
            loadData(){
      
                axios.get('http://localhost:3000/users')
                    .then((res)=>{
      
                    console.log(res);
                    const {
      status,data} = res;
                    if (status == 200) {
      
                        this.list = data;
                    }

                })
            }
        }
    }
script>
<style>

style>

实现效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rTVoAGow-1597388161738)(./assets/1534228452013.png)]

删除功能

点击英雄列表中每个英雄信息后面的删除按钮,可以删除当前英雄数据

步骤分析

  1. 找到删除按钮, 绑定click事件
  2. 将要删除的英雄的id传给删除方法
  3. 在methods中实现删除方法
    1. 获取当前英雄的id
    2. 提示用户是否删除
    3. 如果是, 则调用axios.delete方法删除数据
      1. 删除成功, 重新渲染列表

代码演示

AppList.vue

<template>
    <div>
        <h2 class="sub-header">Hero Listh2>
        <a class="btn btn-success" href="add.html">Adda>
        <div class="table-responsive">
            <table class="table table-striped">

                <thead>
                    <tr>
                        <th>#th>
                        <th>名称th>
                        <th>性别th>
                        <th>操作th>
                    tr>
                thead>
                <tbody>
                    <tr :key="item.id" v-for="(item, index) in list">
                        <td>{
    { index + 1 }}td>
                        <td>{
    { item.name }}td>
                        <td>{
    { item.gender }}td>
                        <td>
                            <a href="edit.html">edita>
                              
                            
                            <a href="#" @click.prevent="handleDelete(item.id)">deletea>

                        td>
                    tr>
                tbody>
            table>
        div>
    div>
template>

<script>
    import axios from 'axios';

    export default {
      
        data(){
      
            return {
      
                list:[]
            }
        },
        created(){
      
            this.loadData();
        },
        methods:{
      
            loadData(){
      
                axios.get('http://localhost:3000/users')
                    .then((res)=>{
      
                    console.log(res);
                    const {
      status,data} = res;
                    if (status == 200) {
      
                        this.list = data;
                    }

                })
            },

            handleDelete(id) {
      
                // 删除提示
                if (!confirm('是否确认删除?')) {
      
                    return;
                }
                axios
                    .delete(`http://localhost:3000/users/${
        id}`)
                    .then((res) => {
      
                    if (res.status === 200) {
      
                        // 删除成功,重新渲染列表
                        this.loadData();
                    } else {
      
                        alert('删除失败');
                    }
                })
                    .catch((err) => {
      
                    console.log(err);
                });
            }
        }
    }
script>
<style>

style>

添加功能-页面

点击添加按钮 进入到添加的组件,输入新英雄信息,点击确定, 回到列表页渲染新数据

我们先让添加的页面显示出来

步骤分析

  1. 新建add.vue组件
  2. 将课程包中的add.html中添加的页面标签放置在add.vue中
  3. 修改路由router.js
    1. 导入add.vue
    2. 注册add.vue
    3. 使用add.vue
  4. 根据效果调整add.vue中的标签

代码演示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuhidUVo-1597388161740)(./assets/1534229426837.png)]

add.vue

<template>
    <div>
        <h2 class="sub-header">Add Heroh2>
        <form>
            <div class="form-group">
                <label for="exampleInputEmail1">Email addresslabel>
                <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
            div>
            <div class="form-group">
                <label for="exampleInputPassword1">Passwordlabel>
                <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
            div>
            <div class="form-group">
                <label for="exampleInputFile">File inputlabel>
                <input type="file" id="exampleInputFile">
                <p class="help-block">Example block-level help text here.p>
            div>
            <div class="checkbox">
                <label>
                    <input type="checkbox"> Check me out
                label>
            div>
            <button type="submit" class="btn btn-success">Submitbutton>
        form>
    div>
template>

<script>
    export default {
      

    }
script>

<style>

style>

router.js

import Vue from 'vue';

// 1. 导入路由
import VueRouter from 'vue-router';

// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';


// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
     
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        {
      name: 'home', path: '/', redirect: {
      name: 'heroes' } },
        // 路由规则
        {
      name: 'heroes', path: '/heroes', component: AppList },
        {
      name: 'bar', path: '/bar', component: Bar },
        {
      name: 'foo', path: '/foo', component: Foo },
        {
      name: 'add', path: '/add', component: Add }

    ]
});

// 3 导出模块
export default router;

AppList

<template>
    <div>
        <h2 class="sub-header">Hero Listh2>
        
        
        <router-link :to="{name:'add'}">添加router-link>
        <div class="table-responsive">
            
        div>
    div>
template>

// 省略

add.vue

<template>
    <div>
        <div>
            <h2 class="sub-header">Add Heroh2>
            <form>
                <div class="form-group">
                    <label for="name">英雄名称label>
                    <input type="text" class="form-control" id="name" placeholder="Name">
                div>
                <div class="form-group">
                    <label for="sex">英雄性别label>
                    <input type="text" class="form-control" id="sex" placeholder="Sex">
                div>
                <button type="submit" class="btn btn-success">Submitbutton>
            form>
        div>
    div>
template>

添加功能-功能实现

有了页面,接下来我们实现添加的功能

步骤分析:

  1. 绑定文本框
  2. 添加按钮注册事件
  3. 发送请求

代码演示:

add.vue

<template>
    <div>  
        <h2 class="sub-header">Add Heroh2>
        <form>
            <div class="form-group">
                <label for="name">英雄名称label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            div>
            <div class="form-group">
                <label for="sex">英雄性别label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            div>
            <button @click.prevent="handleAdd" type="submit" class="btn btn-success">Submitbutton>
        form>
    div>
template>

<script>

    import axios from 'axios'
    export default {
      
        data() {
      
            return {
      
                // 绑定到表单元素
                formData: {
      
                    name: '',
                    gender: ''
                }
            }
        },
        methods:{
      
            handleAdd() {
      
                axios
                    .post('http://localhost:3000/users', this.formData)
                    .then((res) => {
      
                    const {
       status, data } = res;
                    if (status === 201) {
      
                        // 判断添加是否成功
                        // 添加成功,跳转到英雄列表
                        this.$router.push({
       name: 'heroes' });
                    } else {
      
                        alert('添加失败');
                    }
                })
            }
        }
    }
script>

<style>

style>

编辑功能-页面

编辑的页面和添加的页面很像

步骤分析

  1. 新建edit.vue组件
  2. 将add.vue中的代码copy到edit.vue中进行修改
  3. 修改路由router.js
    1. 导入edit.vue
    2. 注册edit.vue
    3. 使用edit.vue
  4. 在AppList中设置router-link 动态参数

代码演示

edit.vue

<template>
    <div>

        <h2 class="sub-header">Edit Heroh2>
        <form>
            <div class="form-group">
                <label for="name">英雄名称label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            div>
            <div class="form-group">
                <label for="sex">英雄性别label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            div>
            <button  type="submit" class="btn btn-success">Submitbutton>
        form>
    div>
template>

<script>

    import axios from 'axios'
    export default {
      
        data() {
      
            return {
      
                // 绑定到表单元素
                formData: {
      
                    name: '',
                    gender: ''
                }
            }
        },
        methods:{
      

        }
    }
script>

<style>

style>

router.js

import Vue from 'vue';

// 1. 导入路由
import VueRouter from 'vue-router';

// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';
import Edit from './components/edit.vue';

// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);

// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
     
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        {
      name: 'home', path: '/', redirect: {
      name: 'heroes' } },
        // 路由规则
        {
      name: 'heroes', path: '/heroes', component: AppList },
        {
      name: 'bar', path: '/bar', component: Bar },
        {
      name: 'foo', path: '/foo', component: Foo },
        {
      name: 'add', path: '/add', component: Add },
        {
      name: 'edit', path: '/edit/:id', component: Edit }
    ]
});

// 3 导出模块
export default router;

AppList


<router-link :to="{name:'edit',params:{id:item.id}}">编辑router-link>

编辑功能-功能实现

步骤分析:

  1. 进入编辑页面,显示当前要编辑的英雄
    1. 获取url上的id,created()
    2. 发送请求获取数据
    3. 绑定文本框
  2. 点击Submit按钮,实现更新功能

代码演示

edit.vue

<template>
    <div>
        <h2 class="sub-header">Edit Heroh2>
        <form>
            <div class="form-group">
                <label for="name">英雄名称label>
                <input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
            div>
            <div class="form-group">
                <label for="sex">英雄性别label>
                <input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
            div>
            <button @click.prevent="handleEdit" type="submit" class="btn btn-success">Submitbutton>
        form>
    div>
template>

<script>

    import axios from 'axios';

    // 1. 进入编辑页面,显示当前要编辑的英雄
    // 1.1 获取url上的id,created()
    // 1.2 发送请求获取数据
    // 1.3 绑定文本框

    // 2. 点击Submit按钮,实现更新功能

    export default {
      
        data() {
      
            return {
      
                formData: {
      
                    name: '',
                    gender: ''
                },
                // 获取url上的id,默认-1
                heroId: -1
            }
        },
        // 组件创建完毕
        created() {
      
            // 获取路由参数
            this.heroId = this.$route.params.id;
            console.log(this.heroId);

            // 调用 获取英雄对象的方法
            this.loadData();
        },
        methods: {
      
            // 根据id,获取英雄对象
            loadData() {
      
                axios
                    .get(`http://localhost:3000/users/${
        this.heroId}`)
                    .then((res) => {
      
                    if (res.status === 200) {
      
                        this.formData = res.data;
                    }
                });
            },
            handleEdit() {
      
                axios
                    .put(`http://localhost:3000/users/${
        this.heroId}`, this.formData)
                    .then((res) => {
      
                    if (res.status === 200) {
      
                        this.$router.push({
       name: 'heroes' });
                    } else {
      
                        alert('修改失败');
                    }
                });
            }
        }
    };
script>

<style>

style>

当前选中导航的样式

选中某个导航时,其样式和其他的不同, 为active的样式

参考文档

router.js

添加 linkActiveClass: ‘active’,全局配置

// 省略
const router = new VueRouter({
     
    linkActiveClass: 'active',
    routes: [
        // { name: 'home', path: '/', redirect: '/heroes' },
        {
      name: 'home', path: '/', redirect: {
      name: 'heroes' } },
        // 路由规则
        {
      name: 'heroes', path: '/heroes', component: AppList },
        {
      name: 'bar', path: '/bar', component: Bar },
        {
      name: 'foo', path: '/foo', component: Foo },
        {
      name: 'add', path: '/add', component: Add },
        {
      name: 'edit', path: '/edit/:id', component: Edit }
    ]
});
// 省略

全局配置axios

axios请求在多个组件中都要使用,

所以, 可以考虑给Vue实例添加axios选项,

这样 所有的组件都可以使用

main.js

// 省略--

// 导入axios
import axios from 'axios';
// 配置所有Vue的实例都具有$http这个成员
Vue.prototype.$http = axios;

new Vue({
     
    el: '#app',
    render: h => h(App),
    // 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
    // router: appRouter
    router
});

将之前在组件中使用axios的位置改成

  1. 去掉import axios from ‘axios’
  2. 将axios. 改成this.$http.

add.vue

<script>

    // import axios from 'axios'
    export default {
     
data() {
     
return {
     
// 绑定到表单元素
formData: {
     
    name: '',
        gender: ''
}
}
},
    methods:{
     
        handleAdd() {
     
            this.$http
                .post('http://localhost:3000/users', this.formData)
                .then((res) => {
     
                const {
      status, data } = res;
                if (status === 201) {
     
                    // 判断添加是否成功
                    // 添加成功,跳转到英雄列表
                    this.$router.push({
      name: 'heroes' });
                } else {
     
                    alert('添加失败');
                }
            })
        }
    }
}
    </script>

配置baseUrl

请求的url中有一部分是一样的, 每次写很麻烦,

所以, 可以使用axios的API 配置baseURl

main.js

// 省略--

// 导入axios
import axios from 'axios';
// 设置baseURL
axios.defaults.baseURL = 'http://localhost:3000/';

// 省略--

在发起this.$http请求的位置, 简化原来的url

add.vue

<script>

    // import axios from 'axios'
    export default {
     
data() {
     
return {
     
// 绑定到表单元素
formData: {
     
    name: '',
        gender: ''
}
}
},
    methods:{
     
        handleAdd() {
     
            this.$http
                .post('users', this.formData)
                .then((res) => {
     
                const {
      status, data } = res;
                if (status === 201) {
     
                    // 判断添加是否成功
                    // 添加成功,跳转到英雄列表
                    this.$router.push({
      name: 'heroes' });
                } else {
     
                    alert('添加失败');
                }
            })
        }
    }
}
    </script>

你可能感兴趣的:(vue)