04 Vue 高级

一.Vue CLI

1. 安装CLI错误和ESLint规范

  • 安装CLI错误可以试试:npm clean cache -force
  • ESLint是js一个更严格的标准,如果不想使用可以在config/index.js中更改useEslint: false
  • npm run build和npm run dev
    在这里插入图片描述
    在这里插入图片描述

2. runtime-compiler和tuntime-only的区别

  • vue程序的执行过程:template – ast – render(渲染) – virtual dom – 真实dom
    在这里插入图片描述
  • 使用runtime-only更加高效在这里插入图片描述
  • 使用render函数会将createElement中的内容把挂载的内容替换掉
new Vue({
  el: '#app',
  // components: { App },
  // template: '<App/>'
  render: function (createElement) {
    // eslint-disable-next-line spaced-comment
    
    //1.普通用法:createElement('标签',{标签属性class:'box'},['hello world'])

    // return createElement('h2',{class:'box'},['hello world']);
    // return createElement('h2',
    // {class:'box'},
    // ['hello world',createElement('button',['按钮'])])

    //2 传入组件对象
    return createElement(App)

  }
})

在这里插入图片描述

  • runtime-only的vue文件中的template最终被编译成一个普通的对象,里面已经将template全部渲染成render函数了。vue文件中的template是由vue-template-compiler处理的。
  • 总结:
    如果在之后的开发中,你依然使用template,就需要选择runtime-compiler
    如果之后你使用的是.vue文件开发,那么可以选择runtime-only

3.Vue CLI3创建项目和目录结构

在这里插入图片描述

  1. 使用Vue CLI3创建项目
  • 初始化项目:vue create my-project
    在这里插入图片描述
    补充:如果想要删除自己的配置,可以去c盘找C:\Users\admin.vuerc,将自己的配置删掉即可。
  1. 目录结构详解
    在这里插入图片描述

4.VueCLI3配置文件的查看和修改

  1. 修改配置文件的三种方式:
  • 启动本地服务 vue ui 使用图形化界面修改配置
  • 项目 – node-modules – @vue – cli-service – webpack.config.js
  • 在项目的目录下创建自己的配置文件,命名是固定的:vue.config.js
  1. 箭头函数的使用和this指向
  • 箭头函数的使用:
<script>
        //箭头函数:也是一种定义函数的方式
        //1. 定义函数的方式:function
        const aaa = function(){

        }
        //2. 对象字面量中定义函数
        const obj = {
            bbb:function () {
                
            },
            bbb(){

            }
        }

        //3. es6中的箭头函数
        // const ccc = (参数列表) => {...}

        //01 无参数无返回值
        const ccc = () => {
            
        }
        //02 带参数和返回值
        const sum = (num1,num2) => {
            return num1 + num2
        }
        //03 放入一个参数
        const power = num => {  //一个参数可以省略括号
            return num * num
        }
        //04 函数中代码数
        //函数中有多行代码
        const test = () => {
            console.log('hello world');
            console.log('hello paopao');
        }
        //函数中有只有一行代码
        const mul = (num1,num2) => num1 * num2  //会把结果返回,可以省略return

        // const demo = () => {console.log('hello demo');}
        const demo = () => console.log('hello demo');
        demo();
        console.log(demo());  //undefined 函数没有返回值
    </script>
  • 箭头函数中this的使用:
	<script>
        //1 什么时候使用箭头函数,一个函数作为参数传入
        // setTimeout(function () {
        //     console.log(this); //window
        // },1000)
        setTimeout(()=>{

        },1000)

        //结论:箭头函数中的this引用的就是最近作用域中的this
        //2. 箭头函数中的this是如何查找的?  --- 向外层作用域中,一层层查找this,直到有this的定义
        
        const obj = {
            //对象中定义函数,一般直接定义,不使用箭头函数
            aaa() {  
                setTimeout(function(){
                    console.log(this);  //window
                }, 1000);  
                setTimeout(() => { 
                    console.log(this);  //obj对象
                }, 1000);
            }
        }
        obj.aaa()
    </script>

二. 路由 Vue-Router

1. 路由

  1. 什么是路由?
    路由就是通过互联的网络把信息从源地址传输到目的地在的活动。
  • 路由提供了两种机制:路由和传送
    路由是决定数据包从来源目的地的路径
    传送将输入端的数据转移到合适的输出端
  • 路由表
    路由表本质上就是一个映射表,决定了数据包的指向
  1. 前端渲染和后端渲染
  • 01 网页发展阶段:前期
    后端(服务端)渲染 jsp / php
    后端路由:后端处理URL和页面的映射关系
    在这里插入图片描述

  • 02 前后端分离阶段
    后端只负责提供数据,不负责任何界面的内容
    前端渲染:浏览器中显示的网页中的大部分内容,都是由前端写的js代码在浏览器中执行,最终渲染出来的网页。
    在这里插入图片描述

  • 前端路由阶段
    SPA页面:simple page web application,单页面富应用,整个网页只有一个html页面。
    核心:改变url,但是页面不进行整体刷新。

2.url的hash和html5的history

  1. url的hash
    URL 的hash也就是锚点(#),本质上是改变window.location的href属性
    我们可以通过直接赋值location.hash来改变href,但是页面不发生刷新。
  2. html5的history模式
  • history.pushState
    我们可以在浏览器使用history.pushState({ },’ ‘,’…’)来改变链接,但是不刷新页面,它是一个结构,可以通过history.back( ) 【出栈】回到上一个链接。
  • replaceState({ },’ ‘,’…’)同样可用来改变链接,但是它是无法回退上一个链接的,已经替换了链接。
  • history.go
    适用于history.pushState,因为我们需要回退。history.back()等价于history.go(-1),history.forward()等价于history.go(1),等同于浏览器界面的前进后退。

3. 认识vue-router

  • 目前前端流行的三大框架,都有自己的路由实现,vue-router是vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
  • vue-router是基于路由和组件的
    路由用来设定访问路径,将路径和组件映射起来
    在vue-router的单页面应用中,页面的路径的改变就是组件的切换
01 安装和使用vue-router
  • 之前vue cli3创建项目已经选择了加入路由,那么创建好的项目已经带有路由了。
    在这里插入图片描述
  • 配置:src–router–index.js
//配置路由相关信息
import VueRouter from 'vue-router'
import Vue from 'vue'

//1.通过vue.use(插件),安装插件
Vue.use(VueRouter)


const routes = [
    //配置映射关系
]
//2.创建VueRouter对象 
const router = new VueRouter({
    //配置路径和组件之间的映射关系
    routes  // ES6增强写法,原:routes:routes  
})

//3. 将router对象传入到vue实例中
export default router

在main.js中使用:默认引用会自己去找router文件夹下的index.js文件
在这里插入图片描述

02 路由映射配置
  • 1.创建路由组件
  • 2.配置路由映射:组件和路径的映射关系
const routes = [
    //配置映射关系 --- 一个映射关系就是一个对象
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    },
]
  • 3.使用路由,通过<router-link>和<router-view>(相当于占位,决定组件展示的位置)
    • <router-link>是一个vue-router已经内置的组件,它会被渲染成一个<a>标签。
    • <router-view>会根据当前的路径,动态渲染出不同的组件。
    • 网页的其他内容,比如顶部的标题/导航,或者底部的一些版权信息等会和<router-view>处于同一个等级。
    • 在路由切换的时候,切换的是<router-view>挂载的组件,其他内容不会发生改变。

在这里插入图片描述

03 路由的默认值和修改为history模式
  1. 默认情况下,应该进入网站的首页,我们希望<router-view>渲染首页的内容,而不是需要用户手动点击才显示。
    如何让路径默认跳转到首页,并且<router-view>渲染首页组件呢?
  • 我们需要多配置一个映射
    path配置的是根路径:/
    redirect是重定向,也就是我们将根路径重定向到/home的路径下
  1. 默认情况下,路径改变使用的URL的hash,如果希望使用HTML5的history模式,需配置mode。
const router = new VueRouter({
    routes,  // 映射关系
    mode:'history'  //默认是hash,改成html5的history模式
})
04 router-link的其他属性补充

在这里插入图片描述

  • 默认<router-link>是渲染为<a>标签,我们可以使用target=" "指定想要渲染成为的标签。
  • replace,默认是使用history.pushState,可以在浏览器前进或后退,如果不希望通过这种方式返回,就可以使用replace属性,这个时候必须点击<router-link>才能切换组件页面。
  • active-class:处于活跃状态时,会自动加上一个router-link-class,我们可以使用这个class来添加样式,如果想要更改这个class名字,可以active-class:自定义类名,这是处于选中的组件链接的router-link-class就会变成你定义的class名字。
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
<router-link to="/about" tag="button" replace active-class="active">关于</router-link>
  • 如果希望同时给很多个<router-link>都设置active-class,我们可以直接在创建路由对象时指定:linkActiveClass:‘active’
const router = new VueRouter({
    ...
    linkActiveClass:'active'
})

但其实我们很少需要去修改一个类的名字。

05 通过代码跳转路由

我们可以不使用<router-link>来实现跳转,而是通过代码来实现:

<template>
  <div id="app">
    <button @click="homeClick">首页</button>
    <button @click="aboutClick">关于</button>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods: {
    homeClick(){
      //通过代码方式修改路径
      // history.pushState() --- 不要这么写!会绕过vue-router
      this.$router.push('/home')  //所有组件都有$router属性
      // this.$router.replace('/home')  //replace不可返回
      console.log("homeClick");
    },
    aboutClick(){
      this.$router.push('/about')
      // this.$router.replace('/about')
      console.log("aboutClick");
    }
  },
}
</script>

三. Vue-Router使用

1. 动态路由的使用

  • 在某些情况下,一个页面的path路径可能是不确定的,eg:user/aaa,除了固定的链接之外,还希望在后面拼接用户的id,这种path和component的匹配关系,称为动态路由(也是路由传递数据的一种方式)
  • 配置:
//在index.js中配置映射关系
{
   path:'/user/:userId',
     component:User
 }

//在App.vue中我们在跳转路径处拼接用户id
<template>
  <div id="app">
    <h2>我是app组件</h2>
    ...
    <router-link v-bind:to="'/user/'+userId">用户</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      userId:'zhangsan'
    }
  },
} ...
</script>
//上面主要是实现链接的拼接



//User.vue,跳转到用户界面后,我们希望在界面显示用户id
<template>
    <div>
        <h2>我是用户界面</h2>
        <p>我是用户的相关信息,heihei</p>
        <h2>{{userId}}</h2>
        <h2>{{$route.params.userId}}</h2>  //$route.params.userId可以直接获取
    </div>
</template>

<script>
export default {
    name:'User',
    computed: {
        userId(){
        	//写在这里必须加this.名称userId是index.js中自己设置的
            return this.$route.params.userId;  //返回处于活跃状态的路由
        }
    },
}
</script>

$router拿到的是我们在index.js中定义的router对象
$route是哪个路由处于活跃状态,获取的就是哪个

2. vue-router懒加载

  1. 路由的懒加载
  • 懒加载:用到时才加载
  • 官方解释:
    当打包构建应用时,js包会变得非常大,影响页面加载
    如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样会更加高效
  1. 打包文件的解析
  1. 路由懒加载的使用
    在这里插入图片描述
  • 我们使用第三种方式来编写:
    在这里插入图片描述
    在这里插入图片描述
    打包项目时会发现js文件夹中多了三个js文件,分别对应我们的三个组件,这样用户请求时就不用一次性加载所有组件,效率会提高。

3.嵌套路由的使用

  1. 实现步骤:
  • 创建对应的子组件,并在路由映射中配置对应的子组件
//index.js
	{
        path:'/home',
        // component:() => import("../components/Home")
        component:Home,
        children:[
            {
                path:'',
                redirect:'news'  //默认显示
            },
            {
                path:'news',   //不可以加/
                component:HomeNews

            },
            {
                path:'message',
                component:HomeMessage
            }
        ]
    },
  • 在组件内部使用<router-view>标签
//Home.vue
<template>
  <div>
      <h2>我是首页</h2>
      <p>我是首页内容,哈哈哈</p>
      <router-link to="/home/news">新闻</router-link>
      <router-link to="/home/message">消息</router-link>
      <router-view></router-view>
  </div>
</template>

4.路由-参数传递

1.传递参数主要有两种类型:params和query

  • params的类型:(之前动态路由的例子)
    配置路由格式:/router/:id
    传递的方式:在path后拼接对应的值
    传递后形成的路径:/router/xxx
    • 可以使用$route.params.id获取对应的值
  • query的类型:
    配置路由格式:/router,普通配置
    传递的方式:对象中使用query的key作为传递方式
    传递后形成的路径:/router?id=xxx
//index.js 配置映射关系
    {
        path:'/profile',
        component:Profile
    }

01 直接在router-link中加入query参数

//App.vue
<router-link :to="{path:'/profile',query:{name:'paopao',age:18,height:1.88}}">档案</router-link>

02 不使用route-link,使用代码进行跳转

//App.vue
<button @click="userClick">用户</button>
<button @click="profileClick">档案</button>

//添加点击事件
userClick(){
      this.$router.push('/user/'+this.userId)
    },
profileClick(){
  this.$router.push({
    path:'/profile',
    query:{
      name:'paopao',
      age:18,
      height:1.88
    }
  })
}

query是一个对象,我们在路径后面跟上query查询的内容,并且同样我们可以在Profile.vue中获取传递的参数:

//Profile.vue
<template>
  <div>
      <h2>我是Profile组件</h2>
      <h2>{{$route.query.name}}</h2>
      <h2>{{$route.query.age}}</h2>
      <h2>{{$route.query.height}}</h2>
  </div>
</template>

  1. router和route的由来
  • 区别:
    * $router为VueRouter实例,想要导航到不同的URL,则使用$router.push方法。
    * $route为当前router跳转对象,里面可以获取name,path,query,params等
  • 它们都是vue的属性,所以我们可以到处使用它们,并且vue还有两个全局组件RouterView和RouterLink,所以我们才能使用这两个组件。

5.vue-router全局导航守卫

  1. 需求:根据不同的页面修改网页的标题
  • 我们可以在每个组件中添加生命周期方法,修改title,但是这样每个组件的代码会显得冗余。
created() {
      console.log('created');
      document.title='用户'
    },
  1. 使用全局导航守卫
  • 导航钩子beforeEach 三个参数解析:
    to:即将要进入的目标的路由对象
    from:当前导航即将离开的路由对象
    next:调用该方法后,才能进入下一个钩子
//index.js

//前置钩子
router.beforeEach((to,from,next) => {
    //从from跳到to
    document.title = to.matched[0].meta.title  //实现点击子路由也显示标题
    // console.log(to);
    next() //下一步,必须调用
})

每一个组件都有自己的meta(元数据:描述数据的数据)和title,to可以获取meta,然后获取里面的title动态修改标题。

to是指去往的那个组件,我们可以给他添加一个meta属性

{
 path:'/profile',
    component:Profile,
    meta:{
        title:'档案'
    },
}
  1. 补充:
  • 后置钩子afterEach,不需要主动调用next()函数
//前置守卫(guard)
router.beforeEach((to,from,next) => {
    //从from跳到to
    document.title = to.matched[0].meta.title  //实现点击子路由也显示标题
    // console.log(to);
    console.log('++++');
    next() //下一步,必须调用
})

//后置钩子(hook)
router.afterEach((to,from) => {
    console.log('-----------');
})

上面使用的导航守卫,被称之为全局守卫,还有其他一些类型的守卫:官网
* 路由独享的守卫
* 组件内的守卫

5.keep-alive

  1. keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
  • router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存。
//Home.vue
<script>
export default {
    name:"Home",
    data() {
      return {
        message:'你好啊',
        path:'/home/news'   //保存路径
      }
    },
    created() {
      console.log('created');
      // document.title='首页'
    },
    destroyed() {
      console.log('destroyed');
    },
    //1. activated和deactivated这两个函数。只有组件被保存了状态,使用了keep-alive时才有效
    activated() {
      console.log('activated');
      this.$router.push(this.path)  //会将上一次保存的path push进来
    },
    deactivated() {
      console.log('deactivated');
    },
    //2. 记录上一次离开状态,使用组件内的导航守卫
    beforeRouteLeave (to, from, next) {
      console.log(this.$route.path);
      this.path = this.$route.path;
      next()
    }
}
</script>
//App.vue
<keep-alive>
 	<router-view></router-view>
</keep-alive>
  1. keep-alive属性介绍
    include - 字符串或正则表达式,只有匹配的组件会被缓存
    exclude - 字符或正则表达式,任何匹配的组件都不会被缓存

四.Tabbar的封装案例

  • 有一些路径名字不好找,我们可以给路径起别名:
//webpack.base.config.js
resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      '@': resolve('src'),
      'assets': resolve('src/assets'),
      'components': resolve('src/components'),
      'views': resolve('src/views'),
    }
  },
  1. 把导航的每一个模块都单独封装成组件,并且配置它们的路由,我们可以根据path来跳转到对应的component。
//router/index.js
import Vue from 'vue'
import Router from 'vue-router'

const Home = () => import('../views/home/Home')
const Category = () => import('../views/category/Category')
const Cart = () => import('../views/cart/Cart')
const Profile = () => import('../views/profile/Profile')

//1. 安装插件
Vue.use(Router)

//2. 创建默认路由
const routes = [
  {
    path:'',
    redirect:'/home'
  },
  {
    path:'/home',
    component:Home
  },
  {
    path:'/category',
    component:Category
  },
  {
    path:'/cart',
    component:Cart
  },
  {
    path:'/profile',
    component:Profile
  }
]

//3. 导出router
export default new Router({
  routes,
  mode:'history'
})

  1. 这是用来承载四个导航组件的导航条,使用了插槽,这样我们可以动态控制加入几个导航组件,并且设置了导航条的样式。
<template>
    <div id="tab-bar">
        <slot></slot>
    </div>
</template>

<script>
export default {
    name:'TabBar'
}
</script>

<style scoped>
    #tab-bar {
    display: flex;
    background-color: #f6f6f6;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    box-shadow: 0 -1px 1px rgba(100,100,100,.2);
  }
  
</style>
  1. 这里是要放在导航条里的单独的导航模块,利用插槽实现我们可以动态添加文字和图标,需要注意的就是计算属性添加,true或者false的判断是根据当前路由是否为处于活跃的路由。
    还有属性以及方法的添加,最好在插槽外面多套一个div,将方法和属性添加在div上,否则自己写的内容替换插槽的时候,会把设置在插槽上的属性替换掉。
<template>
  <div class="tab-bar-item" @click="itemClick">
      <div v-if="!isActive"><slot name="item-icon"></slot></div>
      <div  v-else><slot name="item-icon-active"></slot></div>
        <div :style="activeStyle">
            <!-- 会被自己传的内容替换,所以class不要直接加在插槽上,无效 -->
            <slot name="item-text"></slot>
        </div>
    </div>
</template>

<script>

export default {
    name:'TabBarItem',
    props:{
        path:String,
        activeColor:{
            type:String,
            default:'black'
        }
    },
    data() {
        return {
            // isActive:true
        }
    },
    computed: {
        isActive(){
            return this.$route.path.indexOf(this.path) !==-1  //判断处于活跃的路由有无我item的path
        },
        activeStyle(){
            return this.isActive ? {color:this.activeColor} : {}
        }
    },
    methods: {
        itemClick(){
            this.$router.replace(this.path)
        }
    },
}
</script>

<style>
 .tab-bar-item {
    flex: 1;
    text-align: center;
    height: 49px;
    font-size: 14px;
  }

  .tab-bar-item img {
      height: 24px;
      width: 24px;
      margin-top: 3px;
      margin-bottom: 2px;
      vertical-align: middle;  /* 去掉图片默认距离下3px */
  }

</style>
  1. 最后我们把整个导航条封装成独立的组件,这样就可以直接在App.vue中使用模板,不会让App.vue中的代码太杂。
  • 注意:使用别名找图标,因为是写在模板中的src,所以引用别名时前面还要加~
<template>
  <tab-bar>
  		//使用别名找图标,因为是写在模板中的src,所以引用别名时前面还要加~
      <tab-bar-item path="/home" activeColor="deeppink">
        <img slot="item-icon" src="~assets/img/tabbar/shouye1.svg" alt="">
        <img slot="item-icon-active" src="~assets/img/tabbar/shouye.svg" alt="">
        <div slot="item-text"> 
          首页
        </div>
      </tab-bar-item>
      <tab-bar-item path="/category" activeColor="deeppink">
        <img slot="item-icon" src="../assets/img/tabbar/category1.svg" alt="">
        <img slot="item-icon-active" src="../assets/img/tabbar/category.svg" alt="">
        <div slot="item-text"> 
          分类
        </div>
      </tab-bar-item>
      <tab-bar-item path="/cart" activeColor="deeppink">
        <img slot="item-icon" src="../assets/img/tabbar/gouwuche1.svg" alt="">
        <img slot="item-icon-active" src="../assets/img/tabbar/gouwuche.svg" alt="">
        <div slot="item-text"> 
          购物车
        </div>
      </tab-bar-item>
      <tab-bar-item path="/profile" activeColor="deeppink">
        <img slot="item-icon" src="../assets/img/tabbar/zhanghao1.svg" alt="">
        <img slot="item-icon-active" src="../assets/img/tabbar/zhanghao.svg" alt="">
        <div slot="item-text"> 
          我的
        </div>
      </tab-bar-item>
    </tab-bar>
</template>

<script>
//直接替换App.vue的位置
//import TabBar from './tabbar/TabBar'
//import TabBarItem from './tabbar/TabBarItem'
//引用别名的路径
import TabBar from 'components/tabbar/TabBar'
import TabBarItem from 'components/tabbar/TabBarItem'

export default {
    name:'MainTabBar',
    components:{
      TabBar,
      TabBarItem
    }
}
</script>

<style>

</style>
  1. App.vue
<template>
  <div id="app">
    <router-view></router-view>
    <main-tab-bar></main-tab-bar>
  </div>
</template>

<script>

import MainTabBar from './components/MainTabBar'

export default {
  name: 'App',
  components:{
    MainTabBar
  }
}
</script>


<style>
  @import "./assets/css/base.css";
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值