当前位置: 首页 > news >正文

python全栈-vue框架

python全栈-vue框架

文章目录

  • 前言
    • 环境配置
  • Vue基础知识
    • v-html
    • v-bind
    • {{}}使用 JavaScript 表达式
    • v-if
    • v-show
    • `v-if` vs. `v-show`
    • v-for
    • (item,index)
    • v-on
    • 函数传参
    • 事件修饰符
    • 数组更新
    • v-model
    • v-model的修饰符
    • 计算属性
    • 侦听器
    • 动态设置标签属性值
    • 生命周期函数
  • 组件
    • 创建组件
    • 引入组件
    • 组件的复用
    • props 父传子
    • 自定义事件 子传父
    • 插槽
    • 后备内容
    • 具名插槽
    • 作用域插槽
    • KeepAlive
    • 异步加载组件
    • 处理边界情况
  • 路由
    • 起步
    • router-view
    • router-link页面跳转
    • 动态匹配路由
    • 嵌套路由
    • 编程式导航
    • 命名路由
    • 重定向和别名
    • HTML5 History 模式
  • 路由进阶
    • 导航守卫
    • 路由元信息
    • 路由懒加载
    • vue项目练习
  • Axios网络请求
    • 网络请求的封装
    • 跨域处理
  • Vuex
    • Vuex进阶
    • Mutation
    • Actions
  • 插件
  • 项目打包

vue是前端三大框架之一

前言

开发环境:Node

使用npm管理vue的插件

由于npm是国外的,使用cnpm速度更快,自己安装cnpm

在终端安装cnpm:npm install -g cnpm --registry=https://registry.npmmirror.com

构建工具webpack

环境配置

安装vue CLI工具:npm install -g @vue/cli

创建一个vue项目:vue create myproject

初始化的时候选择babel,还有一个含web的

linter不要勾选。然后回车。

不要保存配置future projects。如果想要保存配置需要命名,方便下一次安装。

  • 运行vue项目:npm run serve

需要去pycharm里面找到刚刚创建的项目,然后打开package.json,找到scripts那个数据,找到serve一行,在最左边有一个运行。点击之后,就会在终端返回两个本地网址:一个是local,一个是network

访问local后面的网址就行,这个就是我们运行的项目了。是实时更新的,我们编写代码的时候,它会不断的重新执行,这样我们就可以看到我们编写的效果了。不用一直重新运行。

也算是个好消息吧,vue只是需要一个运行的平台,不一定要使用vscode。本人一直坚持的pycharm,还能接着使用。pycharm支持python,html,css,js,现在新增vue框架。

项目里面public不要管,img是存放图片的。别乱动。

剩下的都是配置文件,不用操心。

Vue基础知识

其实不用记笔记了,只需要去官网看文档就行。模板语法 | Vue.js

但是,总觉得还是有个笔记比较好。有关知识点的信息,就不写了。

我们需要在app.vue里面学习vue的知识

可以移除hello world.vue文件了,同时在div id是app的容器里面把容器内的内容清空。

现在我们可以在这个div容器里面编写我们的代码了。

在app.vue里面有三个部分,template,script,style

其中template就是我们的html模板部分,

所谓的模板语法就是template+js部分。

<template>
  <div id="app">
    <h3>模板语法</h3>
    <p>{{ msg }}</p>
  </div>
</template>

<script>

export default {
  name: 'App',
  data() {
    return {
      msg: 'Hello World',
    }
  },
  components: {}
}
</script>

就是我们的数据/文本,可以不写在html结构里面,我们在template里面使用两个花括号,在花括号内部写变量名。

然后在js里面,写一个data方法,在写一个返回值,返回值是以键值对的形式。

这样,template里面的msg就获得了js里面给他赋的值。

v-html

就是我们想要插入html标签,但是直接写进入,会被当成文本。需要给盛放标签的容器加一个属性v-html,然后这个标签就可以成功插入了

<p v-html="aaa"></p>
aaa:'<h2>Hello World</h2>'

在vue里面以“v-”开头的属性都是指令

v-bind

动态修改属性的值

<div v-bind:class="aaa">123456</div>
aaa:'box1'

在v-bind后面加上冒号,再跟着属性,任意属性都可以,这里是class,可以是其他的。

属性的值,必须是一个对象。比如aaa,它的值是box1.

好处:我们可以随时修改属性的值。在前端显示的时候,会动态修改。

下面就是前端显示的内容。上面是我们设计的vue框架。

<div class="box1">123456</div>

由于v-bind太常用了,官方优化了一下。

<div :class="aaa">123456</div>

在属性前面加冒号,就是动态属性了。可以不写v-bind了。

{{}}使用 JavaScript 表达式

在双层花括号里面,只能写单个结果的表达式。

比如aaa,或者aaa+1,它可以进行简单的计算,也可以盛放三目表达式,或一个js语句。前提是这个js语句只会返回一个结果。

判断的依据是,能不能单独放在return后面。

v-if

可以根据后面的属性值决定当前标签是否显示,就像display一样。

当v-if后面的对象的值为真就显示,对象的值是假就不显示,

<div :class="aaa" v-if="flag">123456</div>
data() {
    return {
      msg: 'Hello World',
      aaa:'box1',
      flag: false
    }
  },

还有一个细节,在js里面,每一个键值对之间要使用逗号隔开。必须有。

  • v-if的标签后面还可以跟一个含v-else的标签。

当v-if的值为假,v-else的标签就会显示出来。当v-if的值为真,v-else就不会被显示。

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

<div :class="aaa" v-if="flag">123456</div>
<p v-else>654321</p>
  • <template>v-if

因为v-if的机制,可以隐藏或显示一个标签,或者容器。这个容器里面可以放很多内容。我们可以一次显示出来。

现在又想把容器里面的子标签。和这个容器是同一级别。

就是容器隐藏的时候,子标签都隐藏,当容器显示的时候,子标签要和容器是同级的。那么任何一个html标签都无法做到。

所以vue提供了template标签,这个标签也可以当成一个容器。里面可以嵌套很多子标签。当这个容器显示的时候,子标签和这个容器是同级的。

<h3>模板语法</h3>
<p>{{ msg }}</p>
<div :class="aaa" v-if="flag">123456</div>
<template v-else>
  <p>a</p>
  <p>b</p>
  <p>c</p>
  <p>d</p>
</template>

就是template里面的p标签和外面的div标签是同级的。在网页中的结构是同级的。

v-show

和v-if的效果是一样的,都是元素的显示和隐藏。

<div :class="aaa" v-show="flag">123456</div>

但是底层的原理是不一样的,v-if是把整个标签移除,或者添加标签。当移除标签的时候,在网页中是看不到这个标签的。

v-show是基于css的样式display的值。就是这个标签会在网页中显示。同时显示display这个属性。

v-if vs. v-show

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

v-for

这是列表渲染。

首先,我们要拿到一个列表数据。比如result,值是一个列表,外面是中括号,里面的数据都是json格式的。以逗号隔开每个数据。

result:[
  {
    id: 1,
    text:'AAAAAA'
  },
    {
    id: 2,
    text:'BBBBBB'
  },
    {
    id: 3,
    text:'CCCCCC'
  }
]

然后是我们拿到这个数据生成列表。

<ul>
  <li v-for="item in result">{{item.text}}</li>
</ul>

在v-for后面写一个迭代器。就是python里面的for循环迭代器。

这里是item从result里面拿数据。item代表的是数据项,这个数据项里面还有更小的数据,比如id,text。

后面的花括号,就是我们从列表项取出来的数据。如果直接写item,就是整个json格式的数据项展示在页面上。

如果是使用的item.text就是从数据项里面取出text数据的值。比如AAAAAA。

同样的,也可以拿数据项里面的id的值。页面上显示的是键值对的值。

一般来说,会有报错的。

<li v-for="item in result" :key="item.id">{{item.text}}</li>

与v-for搭配的是key属性。因为key属性保证了数据项的唯一。在网页渲染的时候保证不会出错。

key是一个动态属性,因为要随着下标的变化而变化。

(item,index)

在v-for的迭代器里面,item实际上是两个值。

<li v-for="(item,index) in result" :key="index">{{item.text}}--{{index}}</li>

index就是当前数据项的下标。从0开始。

因为整个下标也是唯一的,有些时候,这个下标也可以作为key。

v-on

事件触发的槽函数,需要在与data函数同级的,methods函数里面。

就是事件的槽函数必须在methods里面

<button v-on:click="btnclick"></button>
<p v-if="flag">看不见我</p>
methods:{
    btnclick(){
      this.flag = !this.flag;
    }
  }

通过取反操作,可以让一个标签显示或消失

所有data里面的元素,通过this使用

由于这个绑定指令的高频使用,官方也有一个简写方式@

<button @click="btnclick"></button>

就是@和’v-on:‘是等价的

函数传参

btnclick(e){
  this.flag = !this.flag;
  console.log(e)
}

就是一切函数默认有一个event对象作为参数。

通过这个方法可以直接获取我们点击的列表项。

<ul>
  <li @click="liclick(item.text)" v-for="(item,index) in result">{{item.text}}</li>
</ul>
liclick(text){
  console.log(text)
}

在调用函数的时候可以把列表项的参数传进去,比如这里可以把列表项的文本信息拿到。

<li @click="liclick(item.text,$event)" v-for="(item,index) in result">{{item.text}}</li>
liclick(text,e){
  console.log(text,e)
}

既可以获取列表项的参数,同时还可以获取整个列表项。

事件修饰符

就是阻止浏览器默认事件,比如a标签的跳转行为。

<a @click.prevent href="http://www.baidu.com">点击跳转</a>

就是在事件触发后面加一个后缀。也可以再触发一个槽函数。既阻止了页面跳转,又可以触发函数

<a @click.prevent="btnclick" href="http://www.baidu.com">点击跳转</a>

下面是官方提供的其他修饰符。应该叫事件的附加条件。

<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>

<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>

<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>

<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>

数组更新

btnclick(){
  this.result.push({
    id:1004,
    text:'DDD'
  })
},

我们可以动态的给之前创建的数组添加元素。

官方:Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换一个数组

变更方法,顾名思义,就是会对调用它们的原数组进行变更。相对地,也有一些不可变 (immutable) 方法,例如 filter()concat()slice(),这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的

  • 所有可以改变原始数组的方法比如push,都可以使用。就是实时更新数组。

像是数组合并concat,他们返回的是一个新数组。原数组没有发生改变,就不会实时更新。但是我们通过替换的方式,把原数组替换。

btnclick(){
  this.result = this.result.concat([{id:1005,text: 'EEE'}])
},

反正修改原数组才可以更新页面。

v-model

<form>
  <input type="text" v-model='names'>
  <p>{{names}}</p>
</form>

给输入框添加v-model指令。

后面写上变量名。这个变量名需要在data里面声明一下,就是给个空字符串占位。

我们在输入框输入的内容,可以在p标签里面显示。

常见的输入框,文本框都可以使用。

v-model的修饰符

因为v-model可以实时获取用户输入的内容,可能用户输入的内容很多。触发事件的频率太高,需要使用防抖操作。

官方提供了修饰符。

  • lazy 当用户输入完内容,输入框失去焦点才获取内容。
<input v-model.lazy="msg" />
  • number 用户输入自动转换为数字
<input v-model.number="age" />
  • trim 自动去除用户输入内容中两端的空格
<input v-model.trim="msg" />

计算属性

<p>{{names.split('').reverse().join('')}}</p>

官方的本意是放一些简单的变量,方便我们使用。它确实可以在插值的时候放一些特别复杂的计算式。

但是官方不推荐使用特别复杂的计算式。推出了新概念,计算属性。

<p>{{names.split('').reverse().join('')}}</p>
<p>{{names1}}</p>
computed:{
  names1(){
    return this.names.split('').reverse().join('')
  }
},

这两个p标签的效果是一样的。需要把之前的那一大段内容写在computed方法里面,这个方法和data同级。

也可以在methods里面构造这个方法,但是methods是事件。调用的时候需要有括号执行。

<p>{{names1()}}</p>
methods:{
  names1(){
    return this.names.split('').reverse().join('')
  }
}
  • 像这样调用一个函数也会获得和计算属性相同的结果

就是方法在执行的时候,会重新求值。消耗性能资源很多

侦听器

需要在与data同级的条件下,调用watch方法

在watch里面,你想监听哪个属性,就用哪个属性构建方法。

就是我们在data创建变量,在html中使用这个变量。如果想要监听这个变量的值,就需要在watch里面构建方法。

在watch构造的方法,有两个参数,第一个参数是新属性值,第二个参数是发生变化之前的属性值。

都可以打印出来,前面的参数是当前属性的值。后面的参数是变化之前的值

watch:{
  names:function(newval,oldval){
    console.log(newval,oldval);
  }
},

这里监听的是之前创建的输入框里面的值,names。newval就是输入框内的文本。

动态设置标签属性值

<p :class="{'boxx':true}">aaaaa</p>

就是把class属性变成动态的。注意属性值的结构,一个花括号,然后是引号包住的属性值,再后面是一个冒号,冒号后面是布尔值。布尔值为真的时候,这个属性值就显示在页面上,也就是这个标签有这个属性。布尔值为假,就没有这个属性值

<p :class="['boxx','aaa1']">aaaaa</p>

可以接受一个列表作为class属性对象。就是一次性添加多个属性值。

可以是数组嵌套对象

<p :class="[{'boxx':true},'boxx','aaa1']">aaaaa</p>

生命周期函数

我们在组件的方法里面有四个常用的生命周期函数:

  • created 页面创建
  • mounted 页面渲染
  • undated 页面更新
  • destoryed 页面销毁

常用的是页面渲染mounted

页面渲染时自动执行该方法

组件

创建组件

在components目录里面创建以vue结尾的文件。

在新建文件的template里面创建一个div元素。这个div是这个组件的唯一根元素。不能有同级的div元素。

<script setup>
</script>

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

<style scoped>
</style>

引入组件

在主文件里面的script里面,写import 组件名 from 组件路径 这个是组件引入。

同时在主文件里面的components方法里面写组件名称,这一步的操作叫组件注入。

然后我们就可以在主文件的template标签里面,写<组件名/> 就可以把组件放入了

正常的编译器,你只需要把第三步实现,编译器会自动把组件引入和注入。编译器自动执行前两步操作。

组件的复用

一个组件可以在文件中重复使用。而且每个组件的互相独立,不会有冲突。

比如,我们在组件里面放一个按钮和p标签显示按钮的点击次数。

我们在文件里面添加三次这个组件。我们在点击每一个组件的按钮,只会增加按钮所在组件的点击次数。不会影响其他的组件点击次数。

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>

<template>
  <div>
    <p>这是组件{{ count }}</p>
    <button @click="count+=1">按钮</button>
  </div>
</template>

data必须是函数,使用的变量count也必须是以函数的形式返回,才可以保住组件变量的唯一性。

data() {
	count: 0      错了
}

不可以直接声明使用,必须是函数

props 父传子

组件之间进行数据交互的操作

就是文件给组件传参,还有组件给文件传值

<hello :num="1" />

在文件里面给组件传参。

<p>{{num}}</p>
props: {
    num:{
        type: Number,
        default: 0
    }
}

需要在组件里面的script标签里面,设置props方法与data同级。然后把文件里面传给组件的参数写一下,以对象的方式创建属性type指定参数的类型,default指定参数的默认值。然后这个num参数就可以在组件里面使用了。

我们给哪个组件传参,哪个组件里面的num就显示什么参数。没有传参的组件就显示default默认值

<hello :title="'你好'" />

传递字符串作为参数的时候,字符串需要使用引号包裹

  • props验证规则

就是我们在组件的props方法里面给参数指定的type类型,一旦文件里面传参和组件参数的类型不一致会有报错

type的类型就是:Number数字,string字符串

自定义事件 子传父

组件往文件传参数

vue组件:

<button @click="sendclick">发送按钮</button>
<script>
export default {
  data() {
    return {
      count: 0,
      msg: "sendclicked",
    }
  },
  methods: {
    sendclick(){
      this.$emit('onclick',this.msg) // 第一个参数是父级调用的方法名称,第二个参数是我们给父级的数据
    }
  }
}
</script>

注意methods里面的方法,this指针和$emit。第一个参数是父级调用的方法名称,第二个参数是我们给父级的数据

父级文件调用组件,并接收参数

<hello :title="'你好'" @onclick="onclick" />
methods:{
    onclick(data){
      this.names = data
    }
  },

在父级里面写触发事件,@后面的是组件给他的方法名,后面的值是在父组件里面自定义的方法。可以是同名的方式。

还需要在父级组件里面的methods接收参数,其中data就是从子级组件传过来的内容。这里是把传过来的内容赋值给父级的变量names了

插槽

就是把之前的组件引入的单标签<hello/>,变成闭合的双标签<hello></hello> 并且在这两个标签里面写其他的标签

在组件中使用slot标签,接收主文件传过去的html结构

<template>
  <div>
    <slot></slot>
    <p>这是插槽</p>
  </div>
</template>

这是主文件调用的时候。在组件里面写html标签。

<hello>
  <div>显示文本</div>
</hello>

我们还可以动态设置插槽的内容

<hello>
  <div>{{msg}}</div>
</hello>

msg变量是在主文件中声明的。不是在组件里面声明的

后备内容

<slot>没有传内容</slot>

就是组件里面的slot标签写个文本内容。如果父级文件调用的时候没有传东西过来,就显示这个内容在页面上。如果有内容传过来就显示内容。

具名插槽

在文件中引入组件的时候。需要使用template标签包裹内容。并在template里面使用属性v-slot,属性值是组件里面slot的name属性值。

因为组件里面可以有多个slot标签。还可以选择哪一个slot接收文件的内容。

<template v-slot:header>
  <div>{{msg}}</div>
</template>

下面是插槽标签。可以使用多个slot标签。并且使用name属性。

<slot>没有传内容</slot>
<slot name="header">没有传内容1</slot>
<slot name="footer">没有传内容2</slot>

用这个方法就可以实现文件和组件的互通了

作用域插槽

也叫数据回传

  1. 在组件里面声明一个变量,通过slot标签传给文件。键ddd值demo
<slot :ddd="demo"></slot>
  1. 在文件中接收参数
<template v-slot="d11">{{d11.ddd}}</template>

KeepAlive

在使用component标签进行组件的切换的时候,如果一个组件有多个状态。我们在多次调用组件的时候,希望记录组件上一次使用的状态,比如打开的第二个标签等等。

默认是不保存组件的状态,需要在文件中给可能发生动态切换的组件外部套一层元素KeepAlive。

KeepAlive可以保存组件的状态。作为一种缓存。

<script>
  export default {
    data(){
      return {
        msg:0,
      }
    },
    methods:{
      btnclick(){
        this.msg+=1
      }
    }
  }
</script>

<template>
  <div>
    <p>Hello</p>
    <button @click="btnclick">加数字</button>
    <p>{{msg}}</p>
  </div>
</template>

这是vue子组件。其中msg有一个数值。第一次打开的时候msg是0,但是我们点击按钮之后msg一定不是0.但是我们每次切换组件的时候,msg都会刷新,现在不想刷新了。

<template>
  <div id="app">
    <h3>动态切换</h3>
    <button @click="btnclick">切换内容</button>
    <component :is="sonvue"></component>
  </div>
</template>

<script>

import Hello from "@/components/hello.vue";
import Hello1 from "@/components/hello1.vue";

export default {
  name: 'App',
  data() {
    return {
      sonvue:Hello,
    }
  },
  components: {
    Hello,
    Hello1
  },
  methods:{
    btnclick(){
      if(this.sonvue===Hello){
        this.sonvue=Hello1;
      }else{
        this.sonvue=Hello;
      }
    }
  },
}
</script>

在父文件里面,需要引入import两个子组件。还有组件的components注入。以及一开始就给sonvue赋值指向哪个子组件。这里在data里面一开始给sonvue赋值hello组件。通过点击事件把sonvue重新赋值。

<keep-alive>
  <component :is="sonvue"></component>
</keep-alive>

只需要给调用组件的标签套一个KeepAlive标签,就可以缓存子组件的状态了。

异步加载组件

如果我们设计了很多组件,在用户使用的时候,不一定一开始就要全部加载出来。比如上面的动态组件,在一个标签里面可以含有两个组件。默认加载第一个子组件,但是第二个子组件不一定会被用户使用。如果我们加载了第二个子组件可能造成性能浪费。

所以有一个新方法,只有用户使用到子组件的时候才会加载新的子组件。

// import Hello1 from "@/components/hello1.vue";
const Hello1 = () => import("@/components/hello1.vue");

上面是我们使用component默认加载子组件的方式。下面是异步加载子组件的方式。

下面这种方法只有组件被使用才加载。

处理边界情况

使用美元符号直接操作dom元素(不推荐)

通过$root直接获取主文件的变量

子组件通过$parent.msg可以直接获取父组件的变量值。

因为破坏了层级之间的关系,不推荐使用。

路由

由官方维护

在使用路由之前,都是通过a标签的超链接进行跳转。每一次跳转都需要重新加载新的页面

有了路由之后,页面不再发生跳转,只有视图的切换。用户使用的时候,速度更快。

现在官方文件的安装教程都是vue-router4,适配的是vue3.特别新。但是企业里面可能不会这么快的使用最新版本。所以需要切换到vuerouter3的文件。

  • 项目里面安装

需要在终端里面输入cd 项目名,进入项目,然后在安装vue路由router

在项目里面直接使用npm install vue-router安装路由

  • 在vue文件里面自动安装
<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>

如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:(在main.js里面)

import VueRouter from 'vue-router'
Vue.use(VueRouter)

起步

因为是优化页面跳转,所以在src里面创建一个pages目录,然后创建多个vue文件。

然后在main.js里面配置路由

  1. 实例化路由对象
const router = new VueRouter({
  
})
  1. 定义路由
// 引入页面
import home from './pages/home.vue'
import user from './pages/user.vue'
// 定义路由
const routes = [
  {
    path: '/',
    component: home,
  },
  {
    path: '/user',
    component: user,
  }
]

定义了两个页面,path是网页的路由,component是页面。

然后把两个路由添加到路由对象里面去。

const router = new VueRouter({
  routes
})
  1. 挂载路由
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

把第一步创建的router对象,写入vue对象里面。

现在还无法显示页面,因为没有路由出口。

router-view

需要在app.vue里面添加路由入口。

因为app.vue是vue默认打开的vue页面。

router-view是其他页面加载的位置。

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

在浏览器输入http://localhost:8080/#/打开的就是首页

http://localhost:8080/#/user就是打开第二个页面。

router-link页面跳转

<template>
  <div id="app">
    <router-link to="/">首页</router-link>|
    <router-link to="/user">用户中心</router-link>
    <router-view></router-view>
  </div>
</template>

router-link类似标签a超链接的跳转效果。不过这个是vue路由自带的,官方适配

to后面是url路径

动态匹配路由

识别用户参数,显示用户信息

因为是动态路由了,要改main.js的匹配规则

const routes = [
  {
    path: '/',
    component: home,
  },
  {
    path: '/user/:userid',
    component: user,
  }
]

我们先试着跳转一个用户页面

<router-link to="/user/1001">用户中心</router-link>

这里是直接通过路由跳转,跳转到一个userid是1001的用户。

<p>{{$route.params.userid}}</p>

我们在用户页面,获取信息。前面的两个单词都是前缀。后面的是从路由获取的参数userid

也可以在路由里面填写多个参数,path: ‘/user/:userid/:id’,

<router-link to="/user/1001/12">用户中心</router-link>

这里传递了两个参数,

<p>{{$route.params.userid}}</p>
<p>{{$route.params.id}}</p>

然后在用户页面接收了

嵌套路由

就是在路由里面嵌套路由

下面是一个新闻页面含有两个子页面运动和乒乓,以及盛放视图的标签view

<template>
<div>
  <p>新闻</p>
  <router-link to="/news/sports">体育</router-link>|
  <router-link to="/news/pingpang">娱乐</router-link>
  <router-view></router-view>
</div>
</template>

在main.js里面创建一个路由news,然后使用children后面跟一个数组。

{
  path: '/news',
  component: news,
  children: [
    {
      path: 'Sports',
      component: sports,
    },
    {
      path: 'Pingpang',
      component: pingpang,
    }
  ]
}

编程式导航

用事件去跳转页面$router.push('/') 这里是跳转到首页

$router.replace.('/') 和push的效果是一样的

  • push和replace的区别

push可以缓存页面,可以让浏览器前进后退。

replace是页面覆盖。

感觉页面有必要缓存就用push,没用就用replace

命名路由

就是把路由赋值给一个变量,然后访问这个变量

只需要在main.js里面的各种路由里面指定一个name属性

const routes = [
  {
    path: '/',
    name: 'home',
    component: home,
  },
  {
    path: '/user/:userid/:id',
    name: 'user',
    component: user,
  }
]

然后在routerlink里面把跳转方式改成name:路由变量

<template>
  <div id="app">
    <router-link :to="{name:'home'}">首页</router-link>|
    <router-link :to="{name:'user',params:{userid:'101',id:'10'}}">用户中心</router-link>|
    <router-link :to="{name:'news'}">新闻</router-link>
    <router-view></router-view>
  </div>
</template>

记住第二个用户跳转,里面的参数传递方式。

router.push({ name: 'user', params: { userId: 123 } })

这是通过push跳转

重定向和别名

  • 重定向redirect

访问a页面,默认跳转b页面

还是在routes里面的路由,添加一个属性redirect,在这个属性后面写重定向的新页面。后续在访问的时候,自动打开redirect定义的路由

{
  path: '/news',
  name: 'news',
  component: news,
  redirect:'/news/Sports',
  children: [
    {
      path: 'Sports',
      name: 'Sports',
      component: sports,
    },
    {
      path: 'Pingpang',
      name: 'Pingpang',
      component: pingpang,
    }
  ]
}

比如新闻页面,打开新闻应该默认跳转到具体的新闻页面。而不是空的新闻页面

  • 别名alias

就是给一个页面添加多个路由

{
  path: '/',
  name: 'home',
  alias: '/home',
  component: home,
},

访问根路由是首页,访问home也是首页。

HTML5 History 模式

const router = new VueRouter({
  mode: 'history',
})

需要在实例化路由的时候,添加mode参数

如果是history模式,在访问网页的时候,网址里面就没有#了。

还可以是hash,hash默认就是默认有#。

如果没有#,用户直接输入网址,有可能进不来。还要有其他的配置。

路由进阶

导航守卫

最常用的是前置守卫

下面一共有三个模式的守卫

一个前置,一个后置,一个解析守卫

前置守卫就是在跳转新页面之前进行一个验证,解析守卫和前置的效果是一样的。后置守卫是在页面跳转之后的验证。

由于后置守卫是在页面跳转之后,就没必要验证了,所以只有前两个参数,没有next

  • 全局前置守卫
router.beforeEach((to, from, next) => {
  // ...
})

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next 是否允许页面跳转,如果有这个参数,页面可以随意跳转,如果没有就不能跳转(老师让这么理解的

  • 全局后置守卫

router.afterEach((to, from) => {
  // ...
})
  • 路由独享的守卫

可以在路由配置上直接定义 beforeEnter 守卫:

只给一个路由页面配置守卫

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
  • 组件内守卫

之前的几个守卫只能在路由配置的文件里面设置。

现在的是可以在某一个页面的vue组件里面设置守卫。

路由差不多就是页面,页面就是组件。

下面分别是进入,有参数更新,离开。他们都有三个参数,from,to,next

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }

路由元信息

定义路由的时候可以配置 meta 字段,然后在守卫里面可以验证信息,决定页面是否跳转。

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { islogin: true }
        }
      ]
    }
  ]
})

就是我们可以在定义路由的时候,设置meta属性,比如这里有一个属性islogin,他的属性值是true。

然后我们去设置一个守卫,这里就是给用户界面加一个meta验证,如果触发这个验证,就要有对应的方法去验证。然后进行页面跳转。

router.beforeEach((to, from, next) => {
  // ...
  console.log(from)
  console.log(to)
  if (to.meta.islogin === true) {
    // islogin是需要进行操作,验证用户是否已经登录,不然打不开用户详情的页面
    console.log('需要验证')
    // 假设一个验证字段
    const token1 = true
    if (token1){  // 验证成功就进入用户详情页面
      next()
    }else {
      next('/login')   // 如果验证没通过,就去登录界面
    }
  }
  next()
})
  • 应用场景,订单页面,用户信息页面,都需要基于用户登录之后,才可以进入。不然都要跳转到登录界面,完成登录验证。

路由懒加载

就跟子页面一样,不是所有的内容一次性加载完。为了让用户体验更好,或者优化网页的性能,给用不上的页面设置成懒加载,只有用到的时候,才会加载。

就跟组件里面的异步加载组件一样。不要一次性加载完所有路由。

推荐是除了首页的路由,其他的路由页面都使用懒加载。

{
  path: '/',
  name: 'home',
  alias: '/home',
  component: home
},
{
  path: '/user/:userid/:id',
  name: 'user',
  component:() => user,
  meta: { islogin: true }
},

只需要component:user,在冒号和别名之间加上圆括号和小于等于号就行component:() => user,

主要是影响用户的第一次页面的加载速度

vue项目练习

到此为止,我们就可以在创建vue项目的时候把路由选上了,因为我们已经知道了路由的全部知识。

配置一个vue项目,首先要引入CLI工具,然后创建vue项目,最后是vue路由的配置

由于我们在创建项目的时候选上了路由,项目的结构发生了变化,首先是所有的路由配置,被提取到了router目录的index.js文件里面。

  • 设计底部导航,需要抽象成一个组件,放在每个页面底部

在这个组件里面的style标签加一个scoped属性。我们在style里面设置的样式,只在这一个组件内生效。

  • router-link的精准匹配exact

router-link在跳转页面的时候在浏览器会被翻译成a标签。我们点击这个标签的时候,vue会自动给a标签添加属性。

但是vue的机制有点问题,网址的根路由‘/’会一直含有被点击的属性。这个对我们设计样式很不合适。所以需要在router-link标签添加属性exact,只需要给根路由添加即可,就会精准匹配了。

<router-link exact to="/"></router-link>

请添加图片描述

<template>
<div>
  <div class="navbox">
    <ul>
      <li><router-link exact to="/"><span class="iconfont icon-shouye"></span><br>首页</router-link></li>
      <li><router-link to="/find"><span class="iconfont icon-faxian"></span><br>发现</router-link></li>
      <li><router-link to="/car"><span class="iconfont icon-gouwuche"></span><br>购物车</router-link></li>
      <li><router-link to="/dingdan"><span class="iconfont icon-dingdan"></span><br>订单</router-link></li>
      <li><router-link to="/user"><span class="iconfont icon-geren"></span><br>我的</router-link></li>
    </ul>
  </div>
</div>
</template>
  • 发现页的重定向

请添加图片描述

因为发现页面含有子页面,并且是三个子页面,他本身不显示。所以要用页面重定向

{
  path: '/find',
  name: 'find',
  component: Find,
  redirect: '/find/follow',
  children: [
    {
      path: 'club',
      name: 'club',
      component:Club
    },
      {
      path: 'cook',
      name: 'cook',
      component:Cook
    },
      {
      path: 'follow',
      name: 'follow',
      component:Follow
    }
  ]
}

因为不需要使用图标,顶部导航非常简单

<template>
  <div>
    <div class="navbox">
      <div class="box">
        <ul>
          <li><router-link to="/find/follow">关注</router-link></li>
          <li><router-link to="/find/cook">食谱</router-link></li>
          <li><router-link to="/find/club">美食社</router-link></li>
        </ul>
      </div>
    </div>
  </div>
</template>

Axios网络请求

不仅适用于Vue,所有的前端框架都可以使用

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

  • 安装方法

使用 npm:

npm install axios --save

和安装路由的方法一样,需要cd进入项目再安装

我们只需要一个页面测试网络请求,不需要使用路由,可以不安装。

还需要使用import导入axios

  • get请求方式
mounted() {
    axios.get('https://jsonplaceholder.typicode.com/posts')
        .then(response => {
          // console.log(response.data);
          this.lists = response.data;
        })
        .catch(err => {
          console.error('Error:', err);
        });
  }

上面那个api失效了,反正有点小问题。使用下面这个吧https://jsonplaceholder.typicode.com/posts

这个api返回一堆数据,主要包含title和body

catch是网络请求失败返回的信息

  • post请求
axios.post('https://jsonplaceholder.typicode.com/posts', {
  title: 'foo',
  body: 'bar',
  userId: 1
})
    .then(response => {
      console.log(response.data);
    })
    .catch(err => {
      console.error('Error:', err);
    });

post请求需要在网址后面,跟着一个参数对象,比如这里面的title,body,userId,就是给服务器的参数键值对。

剩下的和get是一样的

  • 参数拼接

一般的服务器会把post请求的网址当成字符串处理。我们需要在传参数的时候,把参数转换成字符串。

需要使用querystring,这个是nodejs自带的库。

const querystring = require('querystring');
axios.post('https://jsonplaceholder.typicode.com/posts', querystring.stringify({
      title: 'foo',
      body: 'bar',
      userId: '1'
    }))
        .then(response => {
          console.log(response.data);
        })
        .catch(err => {
          console.error('Error:', err);
        });

网络请求的封装

为了保护接口,都会对网络请求部分进行封装

  • 拦截器

发送数据的时候,识别到网络的请求方式是post的时候,进行一些参数转换的操作

接收数据的时候,进行一个网络状态码的判断

  • api

具体的api操作,设置一个api目录,里面盛放各种小操作和信息。

这里是设置了一个base的js文件,这个文件存放的是api方法

比如baseurl,就是网址的根路由。也就是域名。

然后是banner,就是我们在banner组件里面需要使用的api了。这里是banner的具体路由。后续在使用的时候,就是base.baseurl+base.banner

哦,把方法和api又独立出来了。一切api操作独立成文件。banner请求需要使用api.getbanner方法,这个方法的原理就是刚刚的路径拼接。

其他的api操作,比如登录,就是api.login。原理是一样的。

跨域处理

有两种解决方案:

  1. 后台解决

使用CORS解决。使用npm安装cors:npm install cors --save

然后在服务器里面添加app.use(cors()),就可以直接解决跨域问题

  1. 前端解决(只能是开发环境下跨域,用户使用的时候不可以

在项目里面添加vue.config.js文件,名称不要变。

然后去官网找devserver.proxy配置参考 | Vue CLI

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: '<url>',
        changeOrigin: true,
        pathRewrite:{
        	'^/api':""
        }
      }
    }
  }
}

以后遇到了跨域就这样解决

Vuex

使用npm安装:npm install vuex --save

也要先进入项目。还需要导入

import Vuex from 'vuex'

Vue.use(Vuex)

还需要像路由一样,注入到底部的new Vue里面和router并列

Vuex 依赖 Promise (opens new window)。如果你支持的浏览器并没有实现 Promise (比如 IE),那么你可以使用一个 polyfill 的库

你可以通过 CDN 将其引入

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
  • 构建一个简单的vuex
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

state是状态值,mutations里面的increment是修改状态值的方法

在所有的组件里面都可以读取这个count的值了。方法是$store.state.count

对于整个项目来说,store就是一个全局属性。

通过store.commit(‘increment’) 就可以修改这个全局属性了

  • 封装vuex

和路由一样,也要封装到一个独立的文件里面,把上面的代码都拿走。

创建一个store目录下面的js文件,通过export default store;把这个文件打出去

最后把这个js文件通过import导入main.js文件

现在知道了原理,在创建项目的时候,也可以勾选vuex了。

Vuex进阶

除了使用$store还要一个官方提供的方法mapState

首先使用import { mapState } from ‘vuex’ 引入

然后在computed里面创建

computed:{
    ...mapState(['count','name'])
}

就是三个点,然后参数是一个数组,数组的元素就是我们在上面创建的全局参数。

通过这个方法,我们在组件里面可以直接使用<p>{{ count }}-{{ name }}</p>

Mutation

是修改状态的,action是有异步的时候使用(可选项

mutation是修改状态的唯一方法,也就是store.commit加方法。this.$store.commit(‘increment’)

组件可以传参.在组件里面可以传一个参数给这个方法,然后可以让状态值的增加大小随着组件的参数而改变。只能改变大小

mutations: {
    increment (state,num) {
      state.count+=num
    }
  }
  • 优化mutation的调用方式

在刚刚的mapState旁边增加一个mapMutations。

在methods里面…mapMutations([‘increment’,‘decrement’])

导入这两个方法。然后就可以使用this直接调用了。this.increment(10)

Actions

刚刚的mutation只能是同步操作,mutation不能有异步操作。所以actions来解决这个问题。

action可以有异步,也可以没有异步。

和mutation都需要在vuex文件里面。和mutation同级。第一个参数必须是context,就和mutation的state一样。

还有调用的时候,不是通过commit,而是dispatch调用

this.$store.dispatch(‘increment1’,10)

  • 优化调用 mapActions

和前面的一样

插件

  • 一个是awesome

是官方维护的插件,托管在GitHub上面。

vuejs/awesome-vue: 🎉 A curated list of awesome things related to Vue.js

  • 一个是element ul

使用vue add element 就可以加载了。进入项目再加载

然后是选择,全引用和按需加载

组件 | Element

在官网中有一个完整组件列表和引入方式

就是把所有组件都引入,引入不是使用,不会占用资源

把这js文件列表复制,替换我们项目的element.js文件。想要哪个用哪个。

  • 使用开关组件

组件 | Element

<el-switch
  v-model="value"
  active-color="#13ce66"
  inactive-color="#ff4949">
</el-switch>
<script>
  export default {
    data() {
      return {
        value: true  
      }
    }
  };
</script>

里面还有一个默认值,true就是开,false就是关

  • 表格效果

组件 | Element

<el-table :data="tableData" style="width: 100%">
    <el-table-column prop="date" label="日期" width="180"></el-table-column>
    <el-table-column prop="name" label="姓名" width="180"></el-table-column>
    <el-table-column prop="address" label="地址"></el-table-column>
</el-table>
<script>
export default {
  data() {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }]
    }
  }
}
</script>

项目打包

在我们运行项目的地方,下一行就是打包命令,直接运行,dist目录就是打包好的项目

默认打包,必须把项目放在服务器根目录

或者去vue的配置文件vue.config.js,使用下面的代码,下面的第一个是你想放在服务器的目录

module.exports = {
  publicPath: process.env.NODE_ENV === 'production'
    ? '/my-project/'
    : '/'
}

如果打算将项目部署到 https://<USERNAME>.github.io/<REPO>/ 上 (即仓库地址为 https://github.com/<USERNAME>/<REPO>),可将 publicPath 设为 "/<REPO>/"

相关文章:

  • Hibernate:让对象与数据库无缝对话的全自动ORM框架
  • CesiumEarth能够本地浏览的三维倾斜模型切片(3DTiles)
  • GESP2025年3月认证C++七级( 第三部分编程题(2)等价消除)
  • 图像形态学操作对比(Opencv)
  • VSCode中选择Anaconda的Python环境
  • java数组06:Arrays类
  • 数据结构--线性表
  • 让你方便快捷实现主题色切换(useCssVar)
  • 【征程 6】工具链 VP 示例中 Cmakelists 解读
  • 创建虚拟环境无法加载到pycharm当conda环境,只能为python环境
  • C语言-字符串操作函数手册:语法、技巧与经典应用
  • FreeRTOS使任务处于挂起态的API
  • 小白学习java第11天(下):多线程详解
  • MergeX亮相GTC2025:开启全球广告流量交易新篇章
  • ​asm汇编源代码之-汉字点阵字库显示程序源代码下载​
  • JAVA——初识JAVA
  • Java学习手册:Java异常处理机制
  • 前端防御性编程
  • java数组08:稀疏数组
  • 【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【论文篇+改进】A题解题全流程(持续更新)
  • 东莞疫情2023/专业seo培训学校
  • 有关网站建设账务处理/东营优化路网
  • 做企业网站织梦和wordpress哪个好/现在如何进行网上推广
  • 阿里云搭建企业网站/开创集团与百度
  • 海盐建设局网站/跨境电商网站
  • 国外做3d h视频网站有哪些/友链对网站seo有帮助吗