自己提供域名做网站,成全视频免费观看在线看收索,网站空间2G一年多少钱,dz增加网站标签学习 Vue.js 应该像学习一门编程语言一样#xff0c;首先要熟练掌握常用的知识#xff0c;而对于不常用的内容可以简单了解一下。先对整个框架和语言有一个大致的轮廓#xff0c;然后再逐步补充细节。千万不要像学习算法那样#xff0c;一开始就钻牛角尖。
前序:
vueAPI的…学习 Vue.js 应该像学习一门编程语言一样首先要熟练掌握常用的知识而对于不常用的内容可以简单了解一下。先对整个框架和语言有一个大致的轮廓然后再逐步补充细节。千万不要像学习算法那样一开始就钻牛角尖。
前序:
vueAPI的风格分为: 选项式和组合式vue2中一般用选项式, 所以文章中讲到的api一般都是组合式
vue3官方推荐用基于 Vite 的构建项目首先安装 node.js, 然后在终端输入 npm create vuelatest根据提示构建项目。npm install 和 npm run dev 分别是下载依赖和运行项目
当然你也可以通过vue ui来构建项目
1、初识vue
1.1、项目结构:
当我们新建一个vue项目时, 整个项目刚开始会有很多.vue, .js, .html .css文件但真正有用的只有index.html, App.vue和一些配置文件
vue组件包含三个区域, 分别用来写html,js(ts),css 其中style的scoped可以让css样式的作用域限定到当前组件
template
/templatescript
/scriptstyle scoped
/style1.2、vue常用函数
createApp():是Vue 3中用来创建一个新的Vue应用实例的方法。它接受一个根组件作为参数并返回一个应用实例。根组件就是export出去的name字符串
mount(): 是把createApp创建的应用实例挂载到一个容器上。 接受的参数容器可以是一个css的选择器
createApp(App).mount(#app) // App.vue文件中
div idapp/div //index.html中
我们刚创建的项目中会有上面的两个文件, 实际上就是创建了一个App实列, 通过id选择器把它挂载到一个div上setup(): 是一个函数, 函数里面可以定义响应式变量、计算属性、方法, 然后把变量, 方法 return 出去, 就可以在该组件的template中使用。 我们一个组件所用到的函数、变量都写在这里面
我们每个组件的name、setup、components...都需要export出去。 其中name是这个组件的名字, 当其他组件要用到当前组件的时候就是要name/,
如下: 在setup函数中定义了name和click方法给当前组件的html使用。 代码中的(用来绑定事件, 包括html所有事件和自定义事件)
templateh1{{ age }}/h1 !-- {{ }} 双大括号将 Vue 实例中的数据绑定到 HTML 元素中 --button clickhandleClickclick/button
/templatescript langts
export default {name : App,setup : () {let age 10;const handleClick () {age 18;}return {name, handleClick}}
}
/script前面讲到setup里面定义的方法变量等都需要return出去之后 html 中才能使用下面这个语法糖可以让我们不用一个个写return
setup语法糖: 在script setup /script中写方法、状态的话不需要把方法或状态return回去, vue会自动帮我们return, 而且也不需要用components注册用到的组件。
ref(): 是一个函数使用 ref 函数可以创建一个包装过的响应式对象使其能够在 Vue 组件中进行响应式数据绑定。ref接受的参数是基本类型、数组、对象类型的。(当参数是对象时, ref内部其实是调用的reactive)
reactive(): 使用 reactive函数可以创建一个包装过的响应式对象reactive接受的参数是对象类型的
响应式数据指的是当我们的变量发生变化的时候, 跟这个变量相关的元素就会自动刷新。 上面的代码中我们点击button的时候会把age 18, 但实际上我们页面显示的时候age还是等于10, 因为age不是响应式的变量 所以我们需要用ref创建age变量, let age ref(10), 这样age发生变化时, 跟age相关的元素也会自动刷新。(需要注意: 在js中使用由ref创建的响应式对象是要加上.value, 比如 age.value在html中则不需要, 可直接写成age)
toRefs和toRef:当我们把一个对象或者变量解构的时候。假设person对象中有name, age const {name, age} person那么此时解构出来的的name和age不再具有响应式。为了使解构出来的仍然具有响应式,那么应该用toRefs或toRef包括起来。 const {name, age} toRefs(person).
computed():是基于其他数据的值计算出来属性并且当这些数据变化时计算属性的值会自动更新
计算属性是基于它们的依赖进行缓存的只在其依赖发生变化时才会重新计算而方法每次调用时都会重新执行。
如下, 如果是基于函数getFullName()计算全名的话当name发生变化是控制台会输出3次1, 如果是用FullNameByComputed的话, 控制台只会输出一个1
span{{ getFullName() }}/spanbr
span{{ getFullName() }}/spanbr
span{{ getFullName() }}/spanbrsetup : () {let firstname ref();let lastname ref();const getFullName () {return firstname.value lastname.value;}const FullNameByComputed computed(() {console.log(1); return firstname.value lastname.value;});return {firstname, lastname, getFullName, FullNameByComputed}
}通过上面的computed创建的FullNameByComputed是一个类似ref创建的对象, 在js(script标签)中要访问FullNameByComputed的话需要FullNameByComputed.value。 如果需要直接修改value的话需要在创建对象的时候传递get和set方法如下
const getFullNameComputed computed({get: () {return firstname.value - lastname.value;},set: (newName) {let name newName.split(-);firstname.value name[0];lastname.value name[1];}});上面代码中当我们FullNameByComputed.value的话, vue会自动调用get方法, 当我们FullNameByComputed.valuenewName的时候会自动调用set方法, 并把等号右边的值传递到set参数中
1.3、常用语法糖
v-model: 是 Vue.js 中用于在表单控件如输入框、复选框、单选按钮等和组件之间创建双向数据绑定 如下: 我们让username和输入框双向绑定, 当用户在输入框中输入字符时, username 就会变成用户输入的值。其中username需要是响应式的变量
input v-modelusername typetext
p{{ username }}/p
let username ref();v-for: 通过 ... in ... 用来遍历数组 如下: 假设我们有一个persons数组, 数组长度是3那么我们可以通过v-for来生成3个li标签。其中对于遍历生成的标签我们需要通过:key“给他绑定一个唯一的key, 一般用id。(注意key前面的:, 不写:的话vue会把person.id当成字符串解析)
li v-forperson in persons :keyperson.id{{ person.name }}/liv-if和v-else就如他们的字面意思, 判断用的
注意: 上面文章和下面文章中用到的函数需要自己引入如computed、ref等等文章中就不再过多赘述了。
2、路由器router
2.1、路由的定义与使用:
通过 Vue Router我们可以轻松地定义路由规则将不同的 URL 映射到不同的组件并在这些组件之间切换通俗的讲就是我们可以让页面在不同的url上显示我们想要显示的组件。
router是路由器的意思, route是路由的意思我们需要给vue的实例创建一个router, 通过createRouter()函数.
const router createRouter({history: createWebHistory(), // 路由器的工作模式, 下面会讲到routes : [{path : /home, // url匹配path的时候路由器会渲染这个路由的组件name : HomeView, // 当前的路由route的名字component : Person, // 路由的组件}, // 后面可以继续写多个route, router匹配时会从前往后匹配{},...]
})使用router:
引入: 我们通过createApp()可以创建一个vue实例, const app createApp(App), 通过app.use(router)使实例使用router。use(router)的参数是我们上面代码用createRouter()创建的
上面我们创建并在实例中使用了router, 但是我们并没有给router说我们要在页面的哪个部分渲染组件, 所以我们要在我们想要渲染的位置写上RouterView/(一般是在App.vue的template的某个地方)。
最后实现的效果就是, 当url跟我们的某个route匹配时vue的router就会自动的在我们指定的渲染位置上渲染url对应的组件
渲染模式
渲染模式分为前端渲染和后端渲染, html中可以通过a href标签实现点击跳转url这是后端渲染。(点击a标签的时候页面会重新加载一下, 感觉不出来的话可以点击F12 选中network, 每次点击时network中会重新加载文件)
vue中我们可以通过router-link to点击跳转/router-link,来代替a标签to相当于href,这就是实现了前端渲染。(当我们点击的时候会发现浏览器并没有重新加载。)(这里不详细讲前后端渲染了)
to的三种写法 router-link to点击跳转/router-link中的to有三种写法.(to前面加上:, 才能让vue不把后面的内容解析成字符串)
to/home:to{path : /home}:to{name: HomeView}
路由模式
Hash 模式路由使用 URL 的 hash#部分来模拟一个完整的 URL实际 URL 的路径部分始终是 # 符号之前的内容History 模式利用 HTML5 History API 来管理路由这使得 URL 看起来像普通的 URL没有 # 符号。
2.2、路由的传参:
一般用第二种。(useRoute()创建的对象中包含query和params) 通过props.query path 传递: 上面我们通过to的第一种写法后面加上?加上我们要传的参数即可(通过分隔要传不同的参数)。router-link :to/home?name${name}router link/router-link或 router-link :to{ path : /home, query: { name, } } router link /router-link, 通过这种方式即可把当前组件中的name传递到要路由到的组件中 接收: 路由组件通过useRoute()创建对象, 对象的query对象中就存着我们传递的数据const route useRoute(); console.log(route.query.name) 通过props.params name 前提我们需要修改router的routes的path路径, 通过用:占位。path : /home/:name。 然后可以通过router-link :to{ name: HomeView, params: { name : 1, } } router link /router-link,或 router-link :to/home/${name}router link/router-link 进行传递 需要渲染的路由组件中通过route.params.name访问
2.3、路由的props配置:
一般传参用上面2.2的第二种写法就行, 下面这个也是一种传参的写法, 只不过不需要用useRoute。
{path : /home/:name,name : HomeView,component : Person,props(route) { // props接收的是当前的路由信息, 里面有path,params,query等等, 你可以输出查看下return route.params;},// props:true, // 等价于 return route.params// props(route) {return route.query}},如上在路由中添加代码中的三种props代码的话就相当于是在Person :namename/, 那么我们就可以通过defineProps来解析出路由中要传的name了。(defineProps3.1中会讲, 注意:每种props写法要对应上面路由的传参对应的传递写法)
2.4、编程式路由:
上面我们都是通过router-link标签的to属性实现跳转, router-link标签相当于html的a标签那么我们只能实现通过点击链接的形式实现跳转, 如果要实现点击button实现跳转那就可以通过管理路由器实现。(通过路由器就可以实现多种形式的跳转)
通过useRouter()创建一个router路由器,router.push()就可以实现跳转push中可传递的参数和2.1中 “to的三种写法” 的参数一样
2.4、路由重定向:
通过在route配置中添加下面代码(/重定向到/home)
{path : /,redirect : /home,
},
{path: /:pathMatch(.*), // 匹配所有路径redirect: /404, //重定向到/404},3、组件传递数据
我们在项目中分别创建Person.vue 和 App.vue, 其中App.vue中使用Person/创建Person组件实例, 即App是Person的父组件
在一般情况下我们父传子的时候用的是下面讲的第一种1. 通过defineProps、子传父的时候用的第二种2. 通过自定义事件
3.1、父组件向子组件传递数据
通过defineProps
父组件中Person :personperson :strstr / 前面我们向子组件中传递了person和str变量, 其中右边的person和str 是我们在父组件script的setup中定义的两个变量, 左边的是 子组件接受时用到的name, 一般命名和父组件中定义时的变量名相同。(个人习惯)
子组件中const AppProps defineProps([person, str]), 其中[]中的两个字符串对应父组件中的name, AppProps 是包含person和str的对象 这样子组件中就可以通过AppProps.person访问
3.2、子组件向父组件传递数据 通过defineProps 在上面父向子传的时候可以让父组件给子组件传递一个get方法, 然后让子组件中用defineProps接收一下这个方法在合适的时候调用, 把要传的数据放到get方法的参数列表 通过自定义事件defineEmits(不只局限于子组件向父组件, 任意两个组件之间都可以) 父组件中定义了get-child-name自定义事件, 给事件绑定了一个函数, 子组件在合适的时机触发get-child-name事件即可
//父组件中
Person get-child-namegetChildName /
const getChildName (ChildName) {console.log(ChildName.value)
}//子组件中
const name ref(child)
const emit defineEmits()
const sendName () {emit(get-child-name, name)
}通过defineExpose可跳过不常用3 父组件中Person refchild_Person /在子组件的实例上添加上ref属性, 然后在setup中定义const child_Person ref();child_Person就是包含子组件暴漏出来的数据的对象(记得ref响应式对象要.value取值)。 (注意: 用child_Person访问子组件的数据时要写在onMounted函数中, onMounted函数可以确保子组件已经被挂载, 不然可能访问不到) 子组件中通过let name hh; let age 18; defineExpose({name, age});, 将自己要暴漏出去的写在defineExpose中
3.3、子组件修改父组件的数据
script setup/script如果是在这个中通过defineProps中过去的父组件数据的话, 可以直接修改父组件的数据
3.4 mitt自定义事件管理库
上面讲到的3.2的第二种自定义事件一般用于子组件和父组件, 但对于层级较深的就需要一层一层传递很麻烦 mitt就可以很好帮我们解决问题
mitt一个js的事件管理库, 一般用于管理自定义事件。(安装指令npm install mitt)
一般在一个js文件中创建一个mitt实例, 在其他要用到自定义事件管理的文件中引入mitter
创建一个新的事件总线实例返回一个包含 on, off, emit, all 等方法的对象用于管理事件的订阅和发布。
const mitter mitt();订阅指定类型的事件当该类型的事件被触发时执行指定的处理函数。
mitter.on(eventName, (data) {console.log(Event received with data:, data);
});取消订阅指定类型的事件停止执行特定的处理函数。
mitter.off(eventName, handlerFunction);触发指定类型的事件并传递可选的事件数据给订阅该事件的处理函数。
mitter.emit(eventName, { message: Hello, mitt! });订阅所有类型的事件当任何类型的事件被触发时执行指定的处理函数。
mitter.all((type, data) {console.log(Event ${type} received with data:, data);
});// 清除所有事件监听器
mitter.all.clear();4、组件之间共享数据Pinia
对于子组件和父组件之间我们可以通过上面讲到的方法实现数据共享但是对于有更深层级的组件我们就需要集中管理状态的方法。Pinia就可以解决这个问题, 安装命令npm install pinia
4.1、数据的定义
在实例中引入pinia, 跟引入router一样
import { createPinia } from pinia
const app createApp(App)
const pinia createPinia();
app.use(pinia)一般来说我们会把要共享的组件的数据的pinia放到一个src文件夹下的store中的js文件中。然后在需要使用的文件中引入js 生成store
import { defineStore } from pinia
// defineStore接收的第一个参数是这个store的id(自己定义)
export const usePersonStore defineStore(Person, {state() {return {name: hello, //return 的就是要共享的数据}}
})如果要使用Person的数据的话就:
import { usePersonStore } from /store/Person
const PersonStore usePersonStore() //PersonStore 是一个对象
//PersonStore 中包含的就有name, PersonStore.name或PersonStore.$state.name4.2、数据的修改
直接修改
PersonStore.name ld通过$patch修改
PersonStore.$patch({name: ld})通过action修改
export const usePersonStore defineStore(Person, {
// 在action中可以写方法, vue会自动维护一个this, 用来访问当前store中的数据actions: {changeName() {this.name ld}},state() {return {name: yxc}}
})PersonStore.changeName() // 对于PersonStore解构出来的数据跟1.2中讲的一样也是不再具有响应式我们可以用storeToRefs来解构。(虽然也可以用toRefs但非常不建议)
4.3、getters
如果我们需要计算和返回基于已有状态state的新数据那么可以在getters中写方法
state() {return {name: yxc,age: 18}},getters: { // vue也会自动维护一个thisdoubleName() {return this.name this.name}}4.4、subscribe
subscribe 是用于监听 store 的状态变化的方法。Pinia 提供了一种简单而直观的方式来订阅状态变化
订阅方法通过 store.$subscribe(callback) 方法来订阅状态变化callback 接受一个参数 mutation可以是状态的变化信息或其他相关内容。
取消订阅订阅方法返回一个取消订阅的函数 unsubscribe()你可以在不需要继续监听状态变化时调用它来取消订阅。
响应式更新Pinia 使用 Vue.js 的响应式系统来管理状态因此任何影响状态的变化都会触发订阅者的回调函数。
PersonStore.$subscribe((mutation, state) {})mutation: 一个对象描述了引起状态变化的 mutation。它包含以下属性
storeId: 发生变化的 store 的 ID。type: 变化的类型通常是 direct直接变化或 patch通过 patch 变化。events: 包含变化详情的数组。
state: 变化后的 store 状态。 学到这里, 你就可以用vue写项目了。 犹豫篇幅太长其他vue中不常用的内容放到下篇文章了
下篇文章地址待更