这是一个学习笔记,基于b站蔡蔡小趴菜的vue教学视频做的
注:CSDN会对段落内的html标签屏蔽,所以本文非代码块的html标签以缺半的形式展示
Vue大致结构如下:
**package-lock.json: ** 在使用 npm 安装包时自动生成的一个文件,它用于锁定当前项目的包的版本,以确保在不同的环境中安装的 包的版本一致
package.json: 项目的配置文件,包含了项目的依赖、脚本命令、版本号等信息。
README.MD: 说明
vite.config.js: Vite 构建工具的配置文件,它用于配置和定制 Vite 项目的构建行为和开发环境
public文件夹: 存放不需要经过Webpack处理的静态资源文件。这些文件会直接复制到构建目录中,并可以在HTML文件中
src文件夹: 源代码
assets文件夹: 用于存放应用需要的静态资源文件,如图片、字体、样式等。这些文件可以在组件中通过相对路径引用 (与public区别是会经过Webpack处理,如果部署在服务器上的话就把静态资源放在这里)
components文件夹: 存放vue组件
App.vue: vue的根组件
index.html: 这个文件里面是最基本的html页面代码,body中有
作为引入vue组件的入口main.js:
import { createApp } from 'vue' //引入创建vue实例的方法
import App from './App.vue // App就是根组件
const app = createApp(App); // 创建 Vue 应用实例——基于根组件创建
app.mount('#app'); // 将应用挂载到 id 为 "app" 的 DOM 元素上(也就是index.html的入口)
view文件夹: 存放vue的页面文件,基于路由进行页面跳转
router文件夹: 路由文件夹
index.js: 路由配置文件,包括路由页面和对应路径
事件处理分为内联事件处理器和方法事件处理器
事件通过 @click = "handler " 或者 v-on:click="methodName"触发
handler处是一段简单的Js代码,为一个可以返回值的表达式
<template>
<h3>内联处理</h3>
<button @click="count++">Add</button>
<p>{{ count }}</p>
</template>
<script>
export default {
data() {
return{
count:0
}
}
}
</script>
和内联事件处理不同,handler是一个方法名,调用methods:{}内的方法
PS:this.可以全局调用data(){}内的变量
<template>
<h3>内联处理</h3>
<button @click="addCount">Add</button>
<p>{{ count }}</p>
</template>
<script>
export default {
data() {
return{
count:0
},
methods:{
addCount(){
this.count++;
}
}
}
}
</script>
也就是说methodName(variable) 可以传递参数
其中,$event 表示传递事件对象
<template>
<h3>事件传参</h3>
<!-- $event 表示事件传参传递了一个event对象 -->
<p @click="getNameHandler(item,$event)" v-for="(item,index) of names" key="index">{{ item }}</p>
</template>
<script>
export default {
// data里的值都可以用this来索引到
data() {
return{
names:["iwen","ime","frank"]
}
},
methods:{
addCount(msg) {
this.count++;
console.log(msg);
},
getNameHandler(name,e){
console.log(name);
console.log(e);
}
}
}
</script>
这里跳过了,好像没啥用
Vue会检测到变更方法对数组的更改,并在页面上同步更新数组,
names.push("Alice")
而替换方法则需要按照以下代码形式使用:
this.numbers1 = this.numbers1.concat(this.numbers2);
会改变原数组的变更方法
不会改变原数组的替换方法
就是:
computed:{
} 内的方法
计算属性的用途:
比如下面这个
标签内来判断itbanzhan.content的数组是否有内容
把三目运算符放在computed内成为方法,有利于代码阅读
性能优化
computed仅会计算一次,而methods内的方法每次调用都会执行一次
也就是说,当这个页面有10个
{{ itbaizhanContent }}
时,computed内的itbaizhanContent()也只会执行一次而methods内的会执行10次
<template>
<h3>{{ itbaizhan.name }}</h3>
<p>{{ itbaizhanContent }}</p>
</template>
<script>
export default{
data(){
return{
itbaizhan:{
name:"百战程序员",
content:["前端","Java","Python"]
}
}
},
//计算属性
computed:{
itbaizhanContent(){
return this.itbaizhan.content.length >0 ? "Yes" : "No";
}
}
}
</script>
跟CSS有关
class绑定还是基于 v-bond ,但是和普通v-bond不同的是
class的v-bond支持绑定数组和对象
<template>
<!-- 单对象绑定 -->
<p :class="{ active: isActive, 'text-danger': hasError }">Class 样式绑定1</p>
<!-- 多对象绑定 -->
<p :class="classObject">Class 样式绑定2</p>
<!-- 数组形式绑定 -->
<p :class="[arrActive, arrHasError]">Class 样式绑定3</p>
<!-- 三目运算符绑定 -->
<p :class="[isActive?'active':'']">Class 样式绑定4</p>
<!-- 数组和对象混合 -->
<p :class="[isActive ? 'active':'',{ 'text-danger':hasError}]">Class 样式绑定5</p>
</template>
<script>
export default {
data() {
return {
isActive: true,
hasError: true,
classObject: {
active: true,
'text-danger': true,
},
arrActive: 'active',
arrHasError: 'text-danger',
}
},
}
</script>
<style>
.active {
font-size: 30px;
}
.text-danger {
color: red;
}
</style>
和class绑定同理,v-bond增强至数组和对象
侦听器可以侦听
data(){
message:“Hello”
}
内定义的变量变化
侦听器是与data()、methods同级的watch:{}
watch内的一个方法对应监听一个变量
且方法名与被监听变量名要一致
watch:{
message(newValue,oldValue){
}
}
<template>
<h3>侦听器</h3>
<button @click="updataHandle">修改数据</button>
</template>
<script>
export default{
data(){
return{
message:"hello"
}
},
methods:{
updataHandle(){
this.message = "World"
}
},
//侦听器
watch:{
//newVlaue是改变之后的数据
//oldValue是改变之前的数据
//函数名必须与侦听的数据对象保持一致
message(newVlaue,oldValue){
//数据发生变化,自动执行的函数
console.log(newVlaue,oldValue)
}
}
}
</script>
v-model
v-model设置在标签里,绑定一个data()内的变量message
绑定的变量message会同步和Input内容更新
<template>
<h3>表单输入绑定</h3>
<form>
<input type="text" v-model="message">
<p>{{ message }}</p>
<input type="checkbox" id="checkbox" v-model="checked">
</form>
<label for="checkbox">{{ checked }}</label>
</template>
<script>
export default{
data(){
return{
message:"",
checked:"false"
}
}
}
</script>
v-bond修饰符
.lazy——只有在change事件后才触发更新
.number——只能接受数字
.trim——消除空格
.lazy:
在输入过程中变量不会和输入一起更新,失去焦点这样的事件触发后才会同步更新
模板引用就是DOM引用
通过给标签设置属性 ref=“container”
后面可以在脚本中使用this.$refs.container,使用原生JS来操控该标签
<template>
<div ref="container" class="container">{{ content }}</div>
<button @click="getElementHandle">获取元素</button>
</template>
<script>
/**
* 内容改变: {{ 模板语法 }}
* 属性改变: v-bond
* 事件: @click=""
*
* 没有特殊需求,不要操控DOM
*/
export default {
data(){
return{
content:"内容"
}
},
methods:{
getElementHandle(){
// innerHTML:原生JS的属性
console.log(this.$refs.container.innerHTML = "hhhhh");
}
}
}
</script>
首先是文件构成和结构
Vue页面分为两种:主文件App.vue和Component文件夹内的.vue文件
Compnent内的.vue文件就是构成页面的组件
主文件和组件文件一般都包含以下三个部分:
<template>
<!-- html -->
</template>
<script>
// JavaScript
</script>
<style>
/* css */
</style>
组件引入
下面是组件Mycomponent引入主文件App.vue的例子
MyComponent:
<template>
<div class="container">{{ message }}</div>
</template>
<script>
export default {
data(){
return{
message:"组件基础组成"
}
}
}
</script>
<style>
.container{
font-size: 30px;
color: brown;
}
</style>
App.vue
<template>
<!-- 3.显示组件 -->
<MyComponent/>
</template>
<script>
//1. 引入组件
import MyComponent from './components/MyComponent.vue';
export default {
//2. 注入组件
components:{
MyComponent
}
}
</script>
<style>
</style>
style scoped
scoped的作用是限制生效作用域,一般用于组件内,使样式只能作用于本组件内的元素,
如果元素被引用,样式不会作用于引用页面的元素
举例:
对于一个组件
ComponentDemo.vue:
<template>
<div class = 'title'>这是一个标题</div>
</template>
<style scoped>
.title{
font-size = 50px;
}
</style>
APP.vue
<template>
<div class = "title">App的标题</div>
</template>
<script>
//1. 引入组件
import MyComponent from './components/MyComponent.vue';
export default {
//2. 注入组件
components:{
MyComponent
}
}
</script>
如果没有scoped,APP.vue内的 标题因为与组件的class都是 title,
会被组件内的style选择器命中,从而会有和组件标题同样的样式
举个例子:
对于下图这个页面:
主要由五个组件构成:Header、Main、Asiede、Article和Item
引用结构:
------Header
App.vue ------Main -----Article
------Aside -----Item
Main组件内import了Article组件
Aside组件内Import了Item组件
App.vue则import了三个组件:Header、Main和Aside
以上便是组件的嵌套关系
分为全局注册和局部注册
局部注册:
就是之前的三步骤,将一个组件引入另一个组件
全局注册:
在main.js内注册,注册后全局都可以在内引入并直接使用
main.js :
import { createApp } from 'vue'
import App from './App.vue'
import Header from './pages/Header.vue'
const app = createApp(App)
//在这之间进行组件注册
// 注册语句
app.component("Header",Header)
app.mount('#app')
尽量使用局部注册,局部注册的父子组件依赖关系比较明确
步骤:在父组件的template中,对子组件的展示标签增加属性,这些属性变量就是要传递过去的值
如果仅以 title="Parent"这种形式赋值,传递过去的数据是String型静态数据
如果想要动态数据,或者是数字、数组和对象型数据,就需要用 :age:" " 进行属性绑定,在data内定义变量的类型和值
Parent.vue
<template>
<h3>Parent</h3>
<Child title="Parent 数据" demo = "测试" :test="msg" :age="age" :names="names" :people="people"/>
</template>
<script>
import Child from './Child.vue';
export default {
data(){
return{
msg:"动态Message",
age:20,
names:["li",'ime'],
people:{
name:"Ak",
age:16
}
}
},
components:{
Child
}
}
</script>
Child.vue
<template>
<h3>Child</h3>
<p>{{ title }}</p>
<p>{{ demo }}</p>
<p>{{ test }}</p>
<p>{{ age }}</p>
<ul>
<li v-for="(item,index) of names" :key="index">{{ item }}</li>
</ul>
<p>{{ people.name }} {{ people.age }}</p>
</template>
<script>
export default {
data(){
return{
}
},
props:["title","demo","test","age","names","people"]
}
</script>
简单props以数组方式接受父组件传递过来的各个变量
如上面:props:[“title”,“demo”,“test”,“age”,“names”,“people”]
如果要对Props进行校验,则要改写成下面的格式:
<script>
export default {
data(){
return{
}
},
props:{
title:{
type:[String,Number,Array,Object],
required:true,
default:"Test"
},
names:{
type:[Array],
default(){
return ["空"]
}
}
}
}
</script>
type:[] 用数组来表示变量的类型限制,变量接收的数据只能是这几种
required: 表示该变量是否是必须的
default则为默认值…注意: 数字、字符串和布尔值可以直接default: ,但是其他类型要函数返回
组件事件就是子组件methods中定义的一个方法,该方法内用this.$emit进行标识
举例:Child.vue 和 ComponentEvent.vue
Child.vue:
通过按钮触发chickEventHandle方法
该方法内的语句 this.$emit标识了该语句就是组件事件触发器
this.$emit() 方法接收一个或两个参数 ,第一个参数是父组件响应方法的方法名,第二个参数是传给父组件响应方法的参数(可选)
<template>
<h3>Child</h3>
<button @click="clickEventHandle">子按钮:传递数据</button>
</template>
<script>
export default {
data(){
return{
msg:"Child数据"
}
},
methods:{
clickEventHandle(){
//自定义事件
this.$emit("myEvent",this.msg)
}
}
}
</script>
ComponentEvent.vue
父组件内,下引用的子组件标签要以
@myEvent=“methodsname” 的形式接收组件事件
其中 myEvent是响应子组件的名字,methodsname是父组件要调用的方法
<template>
<h3>组件事件</h3>
<Child @myEvent="fatherHandle"/>
<p>{{ message }}</p>
</template>
<script>
import Child from './Child.vue';
export default {
components:{
Child
},
data(){
return{
message:""
}
},
methods:{
fatherHandle(data){
this.message = data
}
}
}
</script>
以上,子组件也可以简写为 @click直接调用匿名函数
<button @click="$emit('increaseBy', 1)">
Increase by 1
</button>
一般来说是子父组件的输入v-model绑定
比如子组件Search.vue中有一个输入框,当子组件输入框输入数据时,父组件Main.vue会同步展示
原理:
子组件input框v-model绑定一个变量 search,search与input输入同步更新
同时子组件新增一个watch侦听变量search,同时通过组件事件this.$emit将search每次更新的新值传递给父组件
Search.vue:
<template>
搜索:<input type="text" v-model="search">
</template>
<script>
export default {
data(){
return {
search:""
}
},
watch:{
search(newValue,oldValue){
this.$emit("MainHandle",newValue)
}
}
}
</script>
父组件在子组件标签内进行接收(这里用了简写的函数形式)
Main.vue
<template>
<h3>Main</h3>
<p>搜索内容为:{{ mes }}</p>
<Search @MainHandle="data=>this.mes = data"/>
</template>
<script>
import Search from './Search.vue';
export default {
data(){
return{
mes:""
}
} ,
components:{
Search
}
}
</script>
效果展示:
原理:
父组件A,子组件B
A有一函数Afunction,Afunction接收到的参数会赋值给msg, 声明在组件B标签里 func = “Afunction”
B会通过props设定func为Function,调用func函数,给func赋值,从而实现B的值传递给A(子传父)
ComponentA.vue
<template>
<h3>ComponentA</h3>
<ComponentB :func="Afunction"/>
<p>A: {{ msg }}</p>
</template>
<script>
import ComponentB from './ComponentB.vue';
export default {
data() {
return {
msg:""
}
},
components:{
ComponentB
},
methods:{
Afunction(data){
this.msg = data;
}
}
}
</script>
ComponentB.vue
<template>
<h3>ComponentB</h3>
<p>{{ func("从B传递的数据") }}</p>
</template>
<script>
export default {
data() {
return {
}
},
props:{
func:Function
}
}
</script>
看着挺烦的
感觉这个功能会导致代码阅读混乱(
不学了
插槽实际就是在组件与组件之间,传递html模版,父组件传递给子组件
比如父组件想把 两行标题html代码传递给子组件,从而实现在子组件内展示该代码
实现原理:
父组件
父组件中对子组件标签的引用,由单标签变为双标签
比如子组件Chile.vue
则父组件中对子组件的引用就改为:
在两个子组件标签内放置要传递的Html模板内容
子组件
子组件在的某一位置放置
两个slot标签内部就是父组件传递过来的HTML模板代码,从而在子组件内展示
示例:
App.vue:
<template>
<SlotsBase>
<div>
<h3>插槽标题</h3>
<p>{{ msg }}</p>
</div>
</SlotsBase>
<SlotsTwo>
</SlotsTwo>
</template>
<script>
import SlotsBase from './components/SlotsBase.vue';
export default {
data() {
return {
msg:"插槽内容"
};
},
components: {
SlotsBase,
SlotsTwo
}
}
</script>
<style>
</style>
SlotBase.vue:
<template>
<h3>插槽基础知识</h3>
<slot></slot>
</template>
<script>
export default {
}
</script>
子组件通过插槽可以访问父组件的数据作用域
(上图有显示)
如果父组件通过插槽传递了
//
{{msg}}
而父组件同时在data内定义了msg:“Message”
子组件是可以通过插槽,访问到父组件变量msg的值的
很简单,子组件的两个slot标签内的内容就是缺省显示在屏幕上的,如果插槽传递了模板,则不显示
默认值默认值默认值
插槽可以有名字
这种情况主要用于,父组件向子组件传递多个模板,子组件分别而不是一次性接收这些模板
先看一下下面这种情况
父组件:
<template>
<SlotsTwo>
<div>
<h3>插槽标题</h3>
<p>插槽内容</p>
</div>
</SlotsTwo>
</template>
<script>
import SlotsBase from './components/SlotsBase.vue';
import SlotsTwo from './components/SlotsTwo.vue';
export default {
data() {
return {
};
},
components: {
SlotsTwo
}
}
</script>
<style>
</style>
子组件:
<template>
<h3>Slot1</h3>
<slot></slot>
<h3>Slot2</h3>
<slot></slot>
</template>
<script>
export default {
}
</script>
<style>
</style>
父组件只有一对子组件标签,子组件有两对插槽出口标签
那么最终父组件传递的模板会在子组件中出现两次,如下图
下面进入具名插槽:
具名插槽就是给父组件中不同的插槽起名字,子组件通过插槽的名字锁定,在不同的位置接收插槽
父组件将每一组Slot用标签圈起来,在template标签中给名字
(v-slot)可以简写成#
template v-slot:Slot1> 子组件则通过 slot name=“Slot1”>
分别接收 父组件: 子组件 效果: 原理就是,子组件在标签内增加一个属性存储子组件的一个变量 比如下面的例子 子组件的插槽出口设置了一个属性 sname 这个属性可供父组件调用 子组件: 父组件这里,因为子组件只有一个插槽,父组件设定了子组件插槽的名字: v-slot = “slotp” 此时slotp代表子组件的插槽出口,slotp.sname就是在调用子组件插槽出口的属性 父组件: 具名就是多一个指定名字 原理就是,在基础具名的基础上,#slot1=“slotProps” 这个赋值实际上是给插槽接口赋了个别名,如果不这样赋直接用slot1.msg是无法调用的 父组件 子组件 组件有四个生命周期: 组件创建期、组件挂载期(就是组件渲染在页面的时期)、组件更新期(比如通过按钮触发data的一个变量改变)、组件销毁期 上面代码的效果: 首先补充一个知识: 可以在标签内定义DOM结构引用 //
则可以用this.$refs.name来引用这个p标签结构 这里的知识点是,在页面mounted(渲染)之前,DOM树未形成,所以 this.$refs.name无法获取节点 在一个前端项目中,一般是网页结构先成型,再填充数据, 所以一般网络请求都放置在mounted() 里面 原理: tabComponent变量存储组件名称 可以通过按钮改变tabComponent变量的内容,从而实现组件改变 注意下面三元运算符的运用( App.vue ComponentA.vue ComponentB.vue 蛮重要的 主打一个keep-alive标签 在上一小节中, component :is="tabComponent"标签执行后,组件会从DOM树卸载,也就是进入销毁期 component :is=“tabComponent”>
通过keep-alive标签的设定,组件被切换后不会销毁,而是会保持存活 举例 上一小节的代码中仅ComponentA改变一点: 效果展示: 下面为没有的情况: 初始状态 数据更新 组件转换 从初始状态点击数据更新,A组件的变量变为新数据 再点击组件转换,组件转为ComponentB 转换为B后,再点击组件转换,切回A 注意ComponentA还是老数据 下面为App.vue中对组件标签环绕了 按照上面一样的流程 注意到ComponentA的数据还是新数据,保持不变 总结: 不进行组件存活保持的话 组件卸载后,数据会被销毁 再使用组件切换,组件会被重新装载,此时组件的data会被重新初始化为原来的值 如果组件存活保持的话,反之 正常情况下,一个页面内会将import的组件同时加载(即使这个组件当前不展示,比如切换之前的B组件),在页面上看是网页会一次性请求所有vue组件文件 在大型项目中,为了能够加快项目打开速度,会使用异步组件。也就是说暂时用不到的组件在页面初始化的时候不会加载,而是在组件会被用到的时候被加载 实现只需要在引入的时候改一下引入方式即可: 此时会发现,B组件的请求是在点击组件切换的时候才会发出的 依赖注入是为了解决,props参数传递在多级组件嵌套(比如三层父子嵌套)中数据需要沿着组件关系链多次传递的问题 语法就是 上层 provide一个变量 下层 inject 一个接收 相当于跳过传递链,设置一个中转站 下面举个例子 假设 组件链: App<-- A <-- B <-- C ComponentA.vue ComponentC.vue 效果展示: 在父组件A中 使用了函数式返回值: provider(){ return{ } } 这样可以保证静态数据和Data动态数据都可以注入到子组件中 另一种写法只能保证静态: provider:{ } 路由是基于视图的 视图——view,可以看作不同url的页面,由组件组成 http://localhost:8080/ http://localhost:8080/about 这是两个不同的view 路由的作用就是实现view之间的跳转 实现路由需要以下几步: main.js 文件夹内引入router,vue实例使用router 路由的前提是需要有视图view,src文件夹下创建views文件夹 在views文件夹内新建视图文件 HomeView.vue 和 AboutView.vue src文件夹下创建 router 文件夹 ,router文件夹内创建 index.js 该文件是路由的配置文件,这里又要分几步: App.vue内进行路由展示和路由链接 带参路由比较抽象,字面意思是跳转页面的时候会携带参数 拿例子来说 比如在新闻社分类里面有:百度新闻、网易新闻、头条新闻和搜狐新闻四种链接 点进每一个链接就会展示对应新闻社的介绍,也就是说 这四个链接点击任何一个,都会跳进同一个页面,但是可以通过携带他们对应的参数,从而向后端发送不同的请求来获取页面内容 假设我们新建一个页面 NewsDetailsView.vue 下面是带参路由的配置: index.js NewView.vue(引用了路由链接的页面) NewDetailsView.vue(路由接收参数页面) 可以看到接收方法是 $route.params.name 应用就是,二级导航菜单 简单的说就是index.js里面的一级路径属性里面加一个child 不想写了直接上链接 这里还有一个隐藏知识点 redirect 重定向 也就是默认会跳转到那里
…
…
<template>
<SlotsTwo>
<template v-slot:Slot1>
<h3>插槽标题</h3>
</template>
<template #Slot2>
<p>插槽内容</p>
</template>
</SlotsTwo>
</template>
<script>
import SlotsTwo from './components/SlotsTwo.vue';
export default {
data() {
return {
};
},
components: {
SlotsTwo
}
}
</script>
<style>
</style>
<template>
<h3>Slot1</h3>
<slot name="Slot1"></slot>
<h3>Slot2</h3>
<slot name="Slot2"></slot>
</template>
<script>
export default {
}
</script>
<style>
</style>
插槽数据子传父
<template>
<h3>插槽基础知识</h3>
<slot :sname="content"></slot>
</template>
<script>
export default {
data(){
return{
content:"艾克"
}
}
}
</script>
<template>
<SlotsBase v-slot="slotp">
<h3>{{ slotp.sname }}</h3>
</SlotsBase>
</template>
<script>
import SlotsBase from './components/SlotsBase.vue';
export default {
data() {
return {
};
},
components: {
SlotsBase
}
}
</script>
插槽数据子传父(具名情况下)
<template>
<SlotsAttr>
<template #slot1="slotProps">
<h3>{{ slotProps.msg }}</h3>
</template>
<template #slot2="slotMsg">
<h3>{{ slotMsg.content }}</h3>
</template>
</SlotsAttr>
</template>
<script>
import SlotsAttr from './components/SlotsAttr.vue';
export default {
data() {
return {
};
},
components: {
SlotsAttr,
}
}
</script>
<template>
<h3>子组件传递数据</h3>
<slot name="slot1" :msg="childMessage"></slot>
<h3>内容如下</h3>
<slot name="slot2" :content="content"></slot>
</template>
<script>
export default {
data(){
return{
childMessage:"这是标题",
content:"这是内容"
}
}
}
</script>
组件的生命周期
<template>
<h3>组件的生命周期</h3>
<p>{{ msg }}</p>
<button @click="this.msg='更新之后'">更新按钮</button>
</template>
<script>
/**
* 生命周期函数
* 创建期: beforCreated created
* 挂载期: beforeMount mounted
* 更新期: beforeUpdate updated
* 销毁期: beforeUnmount unmounted
*/
export default {
data(){
return{
msg:"更新之前"
}
},
beforeCreate(){
console.log("组件创建之前")
},
created(){
console.log("组件创建之后")
},
beforeMount(){
console.log("组件渲染之前")
},
mounted(){
console.log("组件渲染之后")
},
beforeUpdate(){
console.log("组件更新之前")
},
updated(){
console.log("组件更新之后");
},
beforeUnmount(){
console.log("组件销毁之前");
},
unmounted(){
console.log("组件销毁之后")
}
}
</script>
生命周期的应用
<template>
<h3>组件生命周期函数应用</h3>
<p ref="name">百战程序员</p>
</template>
<script>
export default {
beforeMount(){
console.log(this.$refs.name)
},
mounted(){
console.log(this.$refs.name)
}
}
</script>
动态组件
vue提供了一个用于展示组件的特殊标签<template>
<component :is="tabComponent"></component>
<button @click="changeHandle">组件转换</button>
</template>
<script>
import ComponentA from './components/ComponentA.vue';
import ComponentB from './components/ComponentB.vue';
export default {
data(){
return{
tabComponent:"ComponentA"
}
},
components:{
ComponentA,ComponentB
},
methods:{
changeHandle(){
this.tabComponent = this.tabComponent =="ComponentA" ? "ComponentB" : "ComponentA"
}
}
}
</script>
<template>
<h3>ComponentA</h3>
</template>
<script>
export default {
}
</script>
<template>
<h3>ComponentB</h3>
</template>
<script>
export default {
}
</script>
组件保持存活
增加一个 message变量和数据更新按钮<template>
<h3>ComponentA</h3>
<p>{{ message }}</p>
<button @click="updateHandle">数据更新</button>
</template>
<script>
export default {
data(){
return{
message:"老数据"
}
},
methods:{
updateHandle(){
this.message = this.message =="老数据" ? "新数据" : "老数据"
}
}
}
</script>
异步组件
import { defineAsyncComponent } from 'vue';
const ComponentB = defineAsyncComponent(() =>
import("./components/ComponentB.vue")
)
依赖注入
<template>
<h3>ComponentA</h3>
<ComponentB />
</template>
<script>
import ComponentB from './ComponentB.vue';
export default {
data(){
return{
msgA:"A的数据(动态)"
}
},
provide(){
return{
message1:this.msgA,
message2:"A的数据(静态)"
}
},
components:{
ComponentB
},
}
</script>
<template>
<h3>ComponentC</h3>
<h3>下面C会接收A的数据</h3>
<p>{{ message1 }}</p>
<p>{{ message2 }}</p>
</template>
<script>
export default {
inject:["message1","message2"]
}
</script>
路由
路由基础
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// .use(router) 声明要使用路由功能
createApp(App).use(router).mount('#app')
// index.js
// 1.引入 vue-router
import {createRouter,createWebHistory} from "vue-router"
// 2.引入需要路由的页面
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
// 配置信息中需要页面的相关配置
// 3.路由页面配置
const routes = [
{
path:'/',
component:HomeView
},
{
path:'/about',
component:AboutView
}
]
// 4.创建路由
const router = createRouter({
/**
* createWebHashHistory
* home: http://localhost:5173/#/
* about: http://localhost:5173/#/about
*
* createWebHistory
* home: http://localhost:5173
* about: http://localhot:5173/about
*
*
*/
history:createWebHistory(),
routes
})
// 5.导出路由
export default router带参路由
<template>
<!-- 路由跳转 -->
<router-link to="/">首页</router-link> |
<router-link to="/about">关于</router-link>
<!-- 路由的显示入口 -->
<router-view></router-view>
</template>
<script>
export default {
}
</script>
带参路由
// 注意到在newsdetails路由后面多了一个key的设置,这个key就作为存储参数的变量,后面接收的时候也使用这个key来接收
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// 首页直接引入,速度快
// 其他页面异步引入
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue')
},
{
path: '/news',
name: 'news',
// 这是异步加载方式,节省内存空间
component: () => import('../views/NewsView.vue')
},
{
// /:name是key
path: '/newsdetails/:name',
name: 'newsdetails',
component: () => import('../views/NewsDetailsView.vue')
}
]
})
export default router
<-- 可以看到下面的to内的传参方式 -->
<template>
<h3>新闻</h3>
<ul>
<li><router-link to="/newsdetails/百度">百度新闻</router-link></li>
<li><router-link to="/newsdetails/网易">网易新闻</router-link></li>
<li><router-link to="/newsdetails/头条">头条新闻</router-link></li>
<li><router-link to="/newsdetails/搜狐">搜狐新闻</router-link></li>
</ul>
</template>
<template>
<h3>新闻详情</h3>
<p> {{ $route.params.name }}</p>
</template>
嵌套路由
// idnex.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
//重定向,就是默认跳转
redirect:"/about/us",
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue'),
children:[
{
//二级导航的路径不要加 '/'
path:"info",
component:() => import("../views/AboutSub/AboutInfo.vue")
},
{
path:"us",
component:() => import("../views/AboutSub/AboutUs.vue")
}
]
}
]
})
export default router
你可能感兴趣的:(vue.js,学习,笔记,前端)