一、文件目录结构
- .vscode ----- vscode工具配置文件
- node_modules ----- vue的依赖文件夹
- public ----- 资源文件夹(浏览器图标)
- src ----- 源码文件夹(assets:公共资源图片css或字体等)
- package.json ----- 信息描述文件
- vite.config.js ----- vue配置文件
二、VUE的模版语法
1、文本插值 {{变量}} :
- 其中也支持一些单一表达式(ps:有返回值)。 例如:
<template>
<p>{{name + 1 > 10 ? "你好!":"你不好"}}</p>
</template>
<script>
export default {
data(){
return{
name: 123
}
}
}
</script>
- 对于插入值的内容也会被转为纯文本对HTML显示(加入需要v-html=‘变量’),例如:
<template>
<p v-html="rahtml"></p>
</template>
<script>
export default {
data(){
return{
rahtml: "<a href='https://www.baidu.com'>百度</a>"
}
}
}
</script>
2、属性绑定 v-bind/:
- 不能使用{{变量}}直接加入属性位置获取,需要使用v-bind,(ps:如果变量属性值为null或者undefined,那么该属性会从元素上移出),同时也支持绑定多个属性,例如:
<template>
<div v-bind:id="dname">完整格式</div>
<div :id="dname">简写</div>
<button :disabled="isDiabled">按钮</button>
<div v-bind="objectAttributes">多属性</div>
</template>
<script>
export default {
data() {
return {
dname: "dname",
isDiabled: false,
objectAttributes:{
id: "id",
class: "class"
}
}
}
}
</script>
3、条件渲染 v-if/v-show
- v-if,指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被染
- v-else
- v-else-if
- v-show
-
ps: v-if和v-show的区别:
(1) v-if是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
(2) v-if也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
相比之下,
(3) v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display属性会被切换. -
总的来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要频繁切换,则使用v-show较好;如果在运行时绑定条件很少改变,则v-if会更合适
例如:
<template>
<div v-if="flag">条件测试</div>
<div v-else-if="!flag">条件2</div>
<div v-else>条件3</div>
<div v-show="flag">条件5 </div>
</template>
<script>
export default {
data() {
return {
flag: true
}
}
}
</script>
4、列表渲染 v-for
使用v-for指令基于一个数组来渲染一个列表语法:item in items,其中也可以使用of命令代替in
例如:
<template>
<div v-for="item in arrays">{{ item }}</div>
<hr>
<div>
<div v-for="item in arraysObject">我叫{{ item.name }},今年{{ item.age }}岁,性别是{{ item.sex }}
<img :src="item.sex">
</div>
</div>
<hr>
<div>
<div v-for="(item,index) of arraysObject">
我叫{{ item.name }},今年{{ item.age }}岁,性别是{{ item.sex }},下标是{{ index }}
</div>
</div>
<hr>
<div>
<div v-for="(value,key,index) of objects">
{{ value }}-{{ key }}-{{ index }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
arrays: ["name1", "name2", "name3"],
arraysObject: [{name: "name1", age: 123, sex: "man"}, {name: "name2", age: 10, sex: "man"}, {
name: "name3",
age: 12,
sex: "woman"
}],
objects: {name: "name1", age: 123, sex: "man"}
}
}
}
</script>
ps:在渲染列表数据时,存在顺序修改,而为了不让vue每次都渲染所有数据,只对修改的数据重新渲染,使用key属性(在真实的场景下一般不会使用index数组索引作为key,而是使用数据的返回的唯一id作为数据key)
例如:
<template>
<div v-for="(item,index) in arrays" :key="index" >{{item}}</div>
</template>
<script>
export default {
data() {
return {
arrays: ["name1", "name2", "name3"]
}
}
}
</script>
5、事件处理 v-on/@
使用v-on(简写@)来监听DOM事件,格式:v-on:click="值"或者@click=“值”
ps:值可以是:内联事件处理器(js代码)或者 方法事件处理器(js方法)
例如:
<template>
<button @click="count++">按钮(内联)</button>
<hr>
<button @click="addCount">按钮(方法)</button>
<div>{{count}}</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
//所有的方法函数都放入methods中
methods:{
addCount(){
console.log("点击!")
//读取data数据使用this.属性
this.count++
}
}
}
</script>
事件参数
作用:
- 在事件方法中有一个默认的方法参数event(就是原生js的event对象)
- 传递数据(再想添加event在第二个参数位置使用$event)
例如:
<template>
<p @click="myclick(item,$event)" v-for="(item,index) in arrays" :key="index">{{item}}</p>
</template>
<script>
export default {
data() {
return {
arrays: ["name1", "name2", "name3"]
}
},
methods:{
myclick(value,event){
console.log("点击数据value:",value)
console.log(event)
}
}
}
</script>
6、事件修饰符(为v-on提供)
- .stop 阻止事件冒泡
- .prevent 阻止默认事件
- .once 事件只会被触发一次
- .enter 回车按键触发
例如:
<template>
<a href="https://www.baidu.com" @click.prevent="myclick">百度</a>
</template>
<script>
export default {
methods:{
myclick(event){
console.log(event)
}
}
}
</script>
7、数组变化侦测
- 变更方法:push(),pop(),shift(),unshift(),splice(),sort(),reverse()使用方法vue会自动重新渲染更改数据数据(会自动更新)
- 替换数组方法:filter(),concat(),slice()这些不会更改原数组
- ps:两个区别就是变更会直接修改原数组数据,而替换数组不会修改原数组方法
8、计算属性 computed
为了不让模版承载太多逻辑
例如:
<template>
<div>{{age}}</div>
<div>{{jisuanage}}</div>
</template>
<script>
export default {
data(){
return{
age: 12
}
},
//计算属性放入的方法
computed:{
jisuanage(){
return this.age > 18 ? "成年!" : "未成年!"
}
}
}
</script>
ps :
- 计算属性(computed):计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算(多次调用只会计算一次)
- 方法(methods):方法调用总是会在重渲染发生时再次执行函数(每次调用每次计算)
9、CLASS绑定 :class
vue对class的v-bind用法提供了特殊的功能增强,表达式也可以是对象和数组
(在数组和对象嵌套使用,只能是数组嵌套对象不能相反)
10、STYLE绑定 :style
跟CLASS绑定一样,vue对其做了一些增强
11、侦听器 watch
对data中数据在页面中使用{{}}展示的数据添加侦听器,侦听变量数据发生变化,从而进一步运行其不同的逻辑操作
<template>
<div>侦听器</div>
<p>{{ massage }}</p>
<button @click="update">点击修改</button>
</template>
<script>
export default {
data() {
return {
massage: "消息!"
}
},
//侦听器
watch: {
//侦听器方法名必须与侦听数据变量名一样
massage(newValue, oldValue) {
//数据发生变化执行
console.log("新值:" + newValue + "旧值:" + oldValue)
}
},
methods: {
update() {
this.massage = "点击修改!"
}
}
}
</script>
12、表单输入绑定 v-model
处理表单中输入框输入数据绑定到对应的变量中(在表单中所有数据都可以绑定)
例如:
<template>
<form>
<input type="text" v-model="massage">
</form>
<div>
{{massage}}
</div>
</template>
<script>
export default {
data() {
return {
massage: ""
}
}
}
</script>
v-model的修饰符
- .lazy 修改每次change事件后跟新数据
- .number 只接受输入的数字
- .trim 获取时去掉前后空格
13、模版引用
在使用的时候需要特殊的ref属性获取dom属性,在vue渲染的时候会被挂载到[this.$refs.属性名]之上,例如:
<template>
<input ref="input" type="text">
<button @click="getDom">getDom</button>
</template>
<script>
export default {
methods: {
getDom() {
console.log(this.$refs.input.value)
}
}
}
</script>
14、组件组成
组件最大优点 可复用(一般定义在单独的.vue文件中)
<!-- 承载标签(必须要的) -->
<template></template>
<script>
//业务逻辑
export default {}
</script>
<!--所有样式 scoped让当前样式只在当前组件生效 -->
<style scoped></style>
引入组件步骤
- 引入组件
- 注入组件
- 显示组件
例如:
<template>
<!-- 第三部显示组件 -->
<MyAssembly></MyAssembly>
</template>
<script>
//第一步 引入vue组件
import MyAssembly from '地址'
export default {
//第二步注入组件
components:{
MyAssembly
}
}
</script>
15、组件嵌套关系
16、组件的注入方式(两种 全局和局部)
正常注册的import都是局部注册组件,全局注册需要再main.js中注册组件就是全局
例如:
//这是main.js引入MyAssembly组件
import { createApp } from 'vue'
//引入
import MyAssembly from './components/MyAssembly.vue'
import App from './App.vue'
var app = createApp(App)
app.component('MyAssembly',MyAssembly) //注入组件
app.mount('#app')
全局注册的问题:
- 全局注册,但并没有被使用的组件无法在生产打包时被自动移除(也叫tree-shaking),也会在js文件中
- 全局注册在大型项目中使用的依赖关系变得不那么明确,影响引用长期的可维护性
17、组件传递数据 props
业务逻辑中使用props以数组的形式加入数据(也可以动态传递,类型也可以是数组对象)属性(ps:父组件传递数据到子组件,不能反着来)
<!--使用MyAssembly组件-->
<template>
<MyAssembly title="你猜我"></MyAssembly>
</template>
<script>
import MyAssembly from './components/MyAssembly.vue'
export default {
components:{
MyAssembly
}
}
</script>
<!--组件的值接收后处理-->
<template>
<div>{{title}}</div>
</template>
<script>
export default {
props:["title"],
}
</script>
18、Props数据校验
ps: props是只读的
<script>
export default {
props:{
//type类型校验,default默认值,request是否必选
title:{type:[String,Number],default:"name",request:true},
//返回对象的数组和对象 需要使用工厂方式的返回
title2:{
type: Object,
default(){
return {
name: "name",
age:12
}
}
}
}
}
</script>
19、组件事件
在组件的模版表达式中,可以直接使用$emit方法触发自定义事件,目的是组件之间数据传递。在父级使用@触发添加自定义事件,通过子级触发父级自定义事件(也可以在第二个参数传入参数,达到从子级传输数据到父级)
<!--父vue-->
<template>
<MyAssembly @chuandi="chuandi2"></MyAssembly>
<div>{{message}}</div>
</template>
<script>
import MyAssembly from './components/MyAssembly.vue'
export default {
data(){
return{
message:""
}
},
components:{
MyAssembly
},
methods:{
chuandi2(data){
console.log("父级"+data)
this.message = data
}
}
}
</script>
<!--子vue-->
<template>
<input type="text" v-model="inputh">
<button @click="chuandi">传递数据</button>
</template>
<script>
export default {
data(){
inputh:""
},
methods:{
chuandi(){
//触发父级的事件,第二个参数传递参数
this.$emit("chuandi",this.inputh)
}
}
}
</script>
- 组件事件和v-model配合使用(利用侦听器实现子传值到父)
<!--子-->
<template>
搜索:<input type="text" v-model="search">
</template>
<script>
export default {
data() {
return {
search: ''
}
},
watch:{
search(newVal, oldVal){
this.$emit('search', newVal)
}
},
}
</script>
<!--父-->
<template>
<h3>Main</h3>
<div> 显示内容:{{search}}</div>
<searchComponent @search="search2"/>
</template>
<script>
import searchComponent from './searchComponent.vue'
export default {
data() {
return{
search: ''
}
},
components: {
searchComponent
},
methods:{
search2(value){
this.search = value
}
}
}
</script>
20、利用函数实现props子传父
使用props的传递函数来(间接)实现,例如:
<!--父-->
<template>
<searchComponent :onEvent="datafn"/>
<div> 显示内容:{{datafn2}}</div>
</template>
<script>
import searchComponent from './searchComponent.vue'
export default {
data() {
return{
datafn2:''
}
},
components: {
searchComponent
},
methods:{
datafn(data){
console.log("数据: "+data)
this.datafn2=data
}
}
}
</script>
<!--子-->
<template>
<div>{{onEvent('传递数据')}}</div>
</template>
<script>
export default {
props:{
onEvent:Function
}
}
</script>
21、透传属性 attribute
当一个组件以单个元素作为渲染,透传的attribute会自动添加到根元素上,常见的class、id、style,禁止可以使用inheritAttrs:false
22、插槽Slots
父组件向子组件传递一些模版片段,让子其在子组件中渲染这些片段,使用标签显示使用,是一个插槽出口,标示了父元素提供的插槽内容将在哪里被渲染
1、渲染作用域
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模版中定义的,例如:
例如:
<!--父-->
<template>
<searchComponent>
<!-- 添加具名方便指定渲染位置-->
<template v-slot:zi>
<div>子组件</div>
</template>
<!-- #简写v-slot-->
<template #message>
<div>{{ message }}</div>
</template>
</searchComponent>
</template>
<script>
import searchComponent from './searchComponent.vue'
export default {
data() {
return {
message: "作用域"
}
},
components: {
searchComponent
}
}
</script>
<!--子-->
<template>
<!-- name指定模块渲染位置 -->
<slot name="zi">插槽默认值</slot>
<hr/>
<slot name="message">插槽默认值</slot>
</template>
2、插槽中同时使用父组件数据和子组件内数据
<!--父-->
<template>
<!-- 使用v-slot起一个变量接收子组件传递的值-->
<searchComponent v-slot="stoltprops">
<!-- <template #message="stoltprops">-->
<div>{{ message }} - 子数据 - {{ stoltprops.datah }}</div>
<!-- </template>-->
</searchComponent>
</template>
<script>
import searchComponent from './searchComponent.vue'
export default {
data() {
return {
message: "作用域"
}
},
components: {
searchComponent
}
}
</script>
<!--子-->
<template>
<!-- 上传数据到父组件再使用显示-->
<slot :datah="message">插槽默认值</slot>
</template>
<script>
export default {
data() {
return {
message: "hello"
}
}
}
</script>
23、组件的生命周期(八个函数方法)
- 创建期:beforeCreate,created
- 挂载期:beforeMount(render),mounted
- 更新期:beforeMount(render),mounted
- 销毁期:beforeDestroy,destroyed
24、动态组件
动态更换组件使用 标签实现
例如:
<template>
<component :is="component"/>
<button @click="clickh">切换组件</button>
</template>
<script>
import searchComponent from './searchComponent.vue'
import MyAssembly from './MyAssembly.vue'
export default {
data() {
return {
component: "MyAssembly"
}
},
components: {
searchComponent,
MyAssembly
},
methods:{
clickh(){
this.component==="MyAssembly"? this.component = "searchComponent": this.component = "MyAssembly"
}
}
}
</script>
25、组件保持存活keep-alive
将component加入 标签中,就是放组件被切换组件不会被卸载了(其中修改的数据就会被修改,而不会重新加载组件显示旧数据)
26、异步组件
//在script中异步加入组件方式
import {defineAsyncComponent} from "vue";
//异步加载组件
const searchComponent = defineAsyncComponent(() => import('./searchComponent.vue'))
27、依赖注入
- 多层级的组件嵌套数据传输,需要一层一层向下传。
- 使用provide和inject解决问题
例如:
<!--父-->
<script>
export default {
provide:{
MyAssembly: "MyAssembly"
}
}
</script>
<!--子-->
<script>
export default {
inject:["MyAssembly"]
}
</script>
ps: provide和inject只能由上往下传递数据,不能反着传递
- 还可以使用全局注入解决
elementApp.provide("MyAssembly2","MyAssembly")
//使用也要在inject引入
28、vue应用
从main.js中创建实例对象createApp(),再通过mount挂载数据到index.html中的div中,可以自定义组件挂载