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

Vue3、vue学习笔记

<!-- `Vue3` -->

1、Vue项目搭建

npm init vue@latest
cd 文件目录
npm i
npm run dev    // npm run _ 这个在package.json中查看scripts
/* vue_study\.vscode可删  // vue_study\src\components也可删除(基本语法,不使用组件) */
// vue_study\.vscode\launch.json
{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"type": "pwa-msedge","request": "launch","name": "Launch Edge against localhost","url": "http:\\localhost:5173","webRoot": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge"}]
}

2、代码风格

<!-- 还是上面的命令 npm run dev -->
<template><div>msg: {{ msg }}</div><button @click="add"> +++ </button>
</template>
​
<script>export default {data() {return {msg: 'Hello Vue!'}},methods: {add() {this.msg += '-杨小槿-'}},}
</script>

vue3阻隔式

<template><div>msg: {{ msg }}</div><button @click="add"> add </button>
</template>
<script>import {ref} from "vue";export default {setup() {const msg = ref("杨小槿")function add(){msg.value = "xxx"}return {/* msg: '杨小槿' //无法操作  */msg,add}}}
</script>

简写

<template><div>msg: {{ msg }}</div><button @click="add"> add </button>
</template>
<script setup>import {ref} from "vue";const msg = ref("杨小槿")function add(){msg.value = "xxx"}
</script>

3、模版语法

插值表达式

<template><div>msg: {{ msg }}</div><div v-text="msg"></div><div v-html="html"></div>
</template>
<script setup>import {ref} from "vue";const msg = ref("杨小槿")const html = ref("<a href='https://www.baidu.com'>百度</a>")
</script>

属性 v-bind

<template><div :data-msg="attr" :class="_class" :style="style">msg: {{ msg }}</div><div v-bind:data-msg="attr" :class="_class2">msg: {{ msg }}</div>
</template>
​
<script setup>import {ref} from "vue";const msg = ref("杨小槿")const attr = ref("吃了吗")const _class = ref("active")const _class2 = {/* class对象形式,为true赋值,flase不赋值 */active: true,isBanner: true,active2: false,}const style = {"color": "blue"}
</script>

动态属性,用于解构(一般不用)

<template><div :data-msg="attr" v-bind="bind">msg: {{ msg }}</div><div v-bind:data-msg="attr" >msg: {{ msg }}</div>
</template>
​
<script setup>import {ref, reactive} from "vue";const msg = ref("杨小槿")const attr = ref("吃了吗")const bind = reactive({/* 也可以不要reactive() */m1: "杨小槿",m2: "任小粟",m3: "庆尘",})
</script>

在插值表达式和动态属性中,都可以写一段js表达式

<div v-bind:data-msg="msg.startsWith('杨小槿') ? '成立' : '不成立'">msg1: {{msg === "杨小槿" ? "成立" : "不成立"}}
</div>

4、条件渲染

  • v-if

  • v-show 控制css display: none

<template><div class="box1" v-if="isShow" style="width: 20px; height: 20px; background-color: cornflowerblue;"></div><div v-else-if="isShow"> 你好 </div><div v-else> 你好呀 </div><div class="box2" v-show="isShow" style="width: 20px; height: 20px; background-color: cornflowerblue;"></div><div> <button @click="isShow=!isShow">显示</button> </div>
</template><script setup>import {ref, reactive} from "vue";const isShow = ref(true)
</script>

5、循环

遍历列表

<template><ul><li v-for="item in list" :key="index">{{item}}</li></ul><ul><li v-for="(item, index) in list" :key="index">{{index}}-{{item}}</li></ul>
</template><script setup>import {ref, reactive} from "vue";const list = ref(["杨小槿", "任小粟", "庆尘", "李叔同"])
</script>

解构,列表

<template><ul><li v-for="(item, index) in list1" :key="item.id">{{item.name}}</li></ul><ul><li v-for="({id, name}, index) in list1" :key="id">{{name}}</li></ul>
</template>
<script setup>import {ref, reactive} from "vue";const list1 = ref([{id: 1, name: "杨小槿"},{id: 2, name: "任小粟"},{id: 3, name: "庆尘"},{id: 4, name: "李书同"}])
</script>

字典

<template><ul><li v-for="val in dict" :key="val">{{val}}</li></ul><ul><li v-for="(val, key) in dict" :key="key">{{key}}-{{val}}</li></ul><ul><li v-for="(val, key, index) in dict" :key="key">{{index}}-{{key}}-{{val}}</li></ul>
</template><script setup>import {ref, reactive} from "vue";const dict = reactive({name: "杨小槿",age: 18,});
</script>

6、事件

可以用v-on(简写@) 来监听DOM事件,事件对象是$event

<template><div><div>count: {{count}}</div><button @click="count ++">count++</button><button @click="add">add</button><button @click="addN(10, $event)">add 10</button></div>
</template><script setup>import {ref} from "vue";const count = ref(0);function add() {count.value++}function addN(n, e){count.value+=nconsole.log(e)}
</script>

事件修饰符

<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<from @submit.prevent="onSubmit"></from>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<from @submit.prevent></from>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 如:事件处理器不来自子元素 -->
<div @click.self="doThis">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为(scrolling)将立即发生而非等待`onScroll`完成 -->
<!-- 以防其中包含`event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>

按键修饰符

<!-- 仅在`key`为`Enter`时调用`submit` -->
<input placeholder="请输入内容" @keydown.enter="submit" />
<div style="background-color: #2c3e50; width: 20px; height: 20px" @mousedown.left="函数名"></div>
<!-- 常用的键盘按键 -->
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
<!-- 鼠标按键 -->
.left
.right
.middle

7、计算属性

<template><div><div>count: {{count}}</div><div>count1: {{count1}}</div><div>count2: {{count2(20)}}</div></div>
</template><script setup>import {ref, computed} from "vue";const count = ref(0);const count1 = computed(()=>{return count.value + 10})const count2 = computed(()=>{return function(num){return count.value + num}})
</script>

8、watch监听属性

ref监听

<template><div><div>msg: {{msg}}</div><input v-model="msg"></div>
</template><script setup>import {ref, watch} from "vue";const msg = ref("");// 可以直接监听一个 refwatch(msg, async(n, o) => {// 新值 n,旧值 oconsole.log(n, o);})
</script>

reactive监听

<template><div><div>msg: {{data.msg}}</div><input v-model="data.msg"></div>
</template><script setup>import {ref, watch, reactive} from "vue";const data = reactive({msg: "",})// 可以直接监听一个 refwatch(data, async(n, o) => {// 新值 n,旧值 oconsole.log(n, o);})
</script>
<template><div><div>msg: {{data.msg}}</div><input v-model="data.msg"></div>
</template><script setup>import {ref, watch, reactive} from "vue";const data = reactive({msg: "",})// 可以直接监听一个 refwatch(()=>data.msg, async(n, o) => {// 新值 n,旧值 oconsole.log(n, o);})
</script>

9、生命周期

setup()
在 beforeCreate 和 created 之前执行,创建的是 data 和 method
onMounted()
在组件挂载完成后执行,可以使用dom
onUpdated()
在组件因为响应式状态变更而更新其 DOM 树之后调用
onUnmounted()
在组件实例被卸载之后调用
onBeforeMount()
在组件被挂载之前被调用
onBeforeUpdate()
在组件即将因为响应式状态变更而更新其 DOM 树之前调用
onBeforeUnmount()
在组件实例被卸载之前调用
onErrorCaptured()
在捕获了后代组件传递的错误时调用
<template>
</template><script setup>export default {setup() {console.log('setup')},beforeCreate() {console.log('beforeCreate')},created() {console.log('created')},beforeMount() {console.log('beforeMount')},mounted() {console.log('mounted')},}
</script>
<template>
</template><script setup>import { onBeforeMount, onMounted } from 'vue';function getData(){console.log('调用后端接口')}console.log('setup1')onBeforeMount(() => {console.log('onBeforeMount')})onMounted(() => {console.log('onMounted')})console.log('setup2')getData()
</script>

10、模版引用

需求:用户进入界面,要求自动选择文本输入框

<template><div><input id="ipt" placeholder="自动选择" /></div>
</template><script setup>import { onMounted } from 'vue';onMounted(() => {const ipt = document.getElementById('ipt');ipt.focus()})
</script>
<template><div><input id="ipt" type="text" ref="defaultIpt" placeholder="自动选择" /></div>
</template><script setup>import { onMounted, ref } from 'vue';const defaultIpt = ref()onMounted(() => {defaultIpt.value.focus()})
</script>

11、vue组件

  • src\components新建文件夹

    • 文件夹下新建numberCilck.vue

<!-- numberCilck.vue -->
<script setup>import { ref } from 'vue';const number = ref(1)function click(){number.value ++}
</script><template><div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped></style>
<!-- src\App.vue -->
<template><div><numberCilck></numberCilck></div>
</template><script setup>import numberCilck from './components/numberCilck.vue';
</script>

全局注册

  • src\main.js

import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'
import numberCilck from './components/numberCilck.vue';  // 加这个const app = createApp(App)
app.component('numberCilck', numberCilck)   //注册组件, 组件名为numberCilck
app.mount('#app')

12、父传子

<!-- src\App.vue -->
<template><div><numberCilck :num="10"></numberCilck><numberCilck ></numberCilck></div>
</template><script setup>
</script>
<!-- numberCilck.vue -->
<script lang="ts" setup>import { ref } from 'vue';interface Props {num?: number   // num是number类型}const props = defineProps<Props>()const {num=1}=props  // num默认值为1const number = ref(1)function click(){number.value += num}
</script><template><div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>
// src\main.js
import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'
import numberCilck from './components/numberCilck.vue';const app = createApp(App)
app.component('numberCilck', numberCilck)   //注册组件, 组件名为numberCilck
app.mount('#app')

<!-- numberCilck.vue -->
<!-- 第二种方法 -->
<script lang="ts" setup>import { ref } from 'vue';interface Props {num?: number   // num是number类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)function click(){number.value += props.num}
</script><template><div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>

在子组件里面,不要尝试修改父组件传递来的props

13、子通知父

用户有没有点击按钮,作为父组件其实是不知道的

如果我想让父组件知道,谁点击了按钮,那么我们可以给子组件编写一个事件

点击按钮之后,就通知父组件

如下,子组件编写

<!-- numberCilck.vue -->
<script lang="ts" setup>import { c } from 'vite/dist/node/types.d-aGj9QkWt';
import { ref } from 'vue';interface Props {num?: number   // num是number类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)const emits = defineEmits(['plus'])  // 定义事件类型function click(){number.value += props.numemits('plus', 1, "你点到了")   // 事件名称,}
</script><template><div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>
<!-- src\App.vue -->
<script setup lang="ts">
import numberCilck from './components/numberCilck.vue';
function plus(num: number, msg: string) {console.log(num, msg);
}
</script><template><div><numberCilck :num="100" @plus="plus"></numberCilck><numberCilck ></numberCilck></div>
</template>

如果是ts子组件也可以这么写

<!-- numberCilck.vue -->
<script lang="ts" setup>import { c } from 'vite/dist/node/types.d-aGj9QkWt';import { ref } from 'vue';interface Props {num?: number   // num是number类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)interface Emits {(e:"plus", num: number, msg: string): void}const emits = defineEmits<Emits>()  // 定义事件类型function click(){number.value += props.numemits('plus', 1, "你点到了")   // 事件名称,}
</script><template>
<div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>

另一种写法

<!-- numberCilck.vue -->
<script lang="ts" setup>import { c } from 'vite/dist/node/types.d-aGj9QkWt';import { ref } from 'vue';interface Props {num?: number   // num是number类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)// interface Emits {//     (e:"plus", num: number, msg: string): void// }const emits = defineEmits<{plus: [number, string]}>()  // 定义事件类型// const emits = defineEmits<Emits>()  // 定义事件类型function click(){ number.value += props.numemits('plus', 1, "你点到了")   // 事件名称,}
</script><template>
<div><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>

14、父传孙

props透传

  • 新建src\components\child.vue

<!-- src\components\child.vue -->
<script lang="ts" setup>
</script><template><div>孙组件</div>
</template>
<style scoped>
</style>
<!-- numberCilck.vue -->
<script lang="ts" setup>import { c } from 'vite/dist/node/types.d-aGj9QkWt';import { ref } from 'vue';import Child from './child.vue';interface Props {num?: number   // num是number类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)// interface Emits {//     (e:"plus", num: number, msg: string): void// }const emits = defineEmits<{plus: [number, string]}>()  // 定义事件类型// const emits = defineEmits<Emits>()  // 定义事件类型function click(){ number.value += props.numemits('plus', 1, "你点到了")   // 事件名称,}
</script><template><div><Child></Child><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>
<!-- src\components\child.vue -->
<script lang="ts" setup>
const props = defineProps(['msg'])
</script><template><div>孙组件{{ props.msg }}</div>
</template>
<style scoped>
</style>
<!-- numberCilck.vue -->
<script lang="ts" setup>import { c } from 'vite/dist/node/types.d-aGj9QkWt';
import { ref } from 'vue';
import Child from './child.vue';interface Props {num?: number   // num是number类型msg: string    // msg是string类型}const props = withDefaults(defineProps<Props>(), {num: 1,})// 定义props类型const number = ref(1)// interface Emits {//     (e:"plus", num: number, msg: string): void// }const emits = defineEmits<{plus: [number, string]}>()  // 定义事件类型// const emits = defineEmits<Emits>()  // 定义事件类型function click(){ number.value += props.numemits('plus', 1, "你点到了")   // 事件名称,}
</script><template><div><Child :msg="props.msg"></Child><div>{{ number}}</div><button @click="click">+</button></div>
</template><style scoped>
</style>
<!-- src\App.vue -->
<script setup lang="ts">
import numberCilck from './components/numberCilck.vue';
function plus(num: number, msg: string) {console.log(num, msg);
}
</script><template><div><numberCilck :num="100"  :msg="'hello'" @plus="plus"></numberCilck><numberCilck :msg="'world'" ></numberCilck></div>
</template>

为了简化,可以使用provideinject进行依赖注入

<!-- 父组件 -->
<!-- src\App.vue -->
<script setup lang="ts">import numberCilck from './components/numberCilck.vue';import {provide} from 'vue'provide('msg','hello!')  // 注入名    值
</script><template><div><numberCilck :num="100"></numberCilck><numberCilck></numberCilck></div>
</template>
<!-- 中间组件 -->
<template><div>我是中间层<Child></Child></div>
</template><script setup lang="ts">import Child from './child.vue';
</script>
<!-- 孙组件 -->
<!-- src\components\child.vue -->
<script lang="ts" setup>import {inject} from 'vue'const msg = inject('msg', "")// const msg = inject('msg', "默认值”)  // 设置默认值
</script><template><div>孙组件{{ msg }}</div>
</template>
<style scoped>
</style>

15、兄弟组件通信

  1. 路由参数

  2. 本地存储

  3. vuexpinia

  4. 全局事件总线(需要用到mitt第三方包)

标签云组件中,点击某个标签,给当前路由加上查询参数,带上选择的标签

然后在文章列表组件中,监听路由查询参数的变化,有变化就从里面取值

然后再查一遍文章列表

16、v-model

<!-- src\App.vue -->
<script setup lang="ts">import {ref} from 'vue'const ipt = ref('hello')
</script><template><div><span>{{ipt}}</span><input v-model="ipt"></div>
</template>

其实vue背后做了很多事

<!-- src\App.vue -->
<script setup lang="ts">import {ref} from 'vue'const ipt = ref('hello')function iptInput(e : InputEvent){let val = (e.target as HTMLInputElement).valueipt.value = val}
</script><template><div><span>{{ipt}}</span><input :value="ipt" @input="iptInput"></div>
</template>

若自己的组件也想实现v-model怎么办

单个v-model

<!-- src\components\myIpt.vue -->
<script setup lang="ts">const props = defineProps(["modelValue"])const emits = defineEmits(["update:modelValue"])function input(e: Event): void {const val = (e.target as HTMLInputElement).valueemits("update:modelValue", val)}
</script><template><div><span>{{ props.modelValue }}</span><input type="text" :value="props.modelValue" @input="input" /></div>
</template><style scoped>
</style>
<!-- src\App.vue -->
<script setup lang="ts">import {ref} from 'vue'import MyIpt from './components/myIpt.vue';const ipt = ref('hello')</script><template><div><MyIpt v-model="ipt"></MyIpt></div>
</template>

多个v-model

<!-- App.vue --> 
<script setup Tang="ts">import {ref} from "vue";import MyIpt from "@/components/myIpt.vue";import AModel from "@/components/aModel.vue";const ipt = ref("你好")const visible = ref(false)
</script>
<template><div><my-ipt v-model="ipt"></my-ipt><AModal v-model:visible="isible"></AModal></div>
</template>
<!-- components/aModel.vue -->
<script setup lang="ts">const props = defineProps(["visible"])const emits = defineEmits(["update:visible"])
</script>
<template><div>{{ props.visible }}<button @click="emits('update:visible', !props.visible)">点我</button></div>
</template>
<style scoped>
</style>

17、组件的插槽

默认插槽

<!-- components/mySlot.vue -->
<script setup lang="ts">    
</script><template><div><div>模态框头部</div><div><slot>这里写默认内容</slot></div><div>模态框尾部</div></div>
</template><style scoped>
</style>
<!-- App.vue --> 
<script setup lang="ts">import Myslot from "@/components/myslot.vue";
</script><template><div><!-- <my-slot><a>这是我的身体 你快出去</a></my-slot> --><my-slot></my-slot></div>
</template>

具名插槽

<!-- components/mySlot.vue -->
<script setup lang="ts">    
</script><template><div><div><slot name="header">模态框头部</slot></div><div><slot name="body">这里写默认内容</slot></div><div>模态框尾部</div></div>
</template><style scoped>
</style>
<!-- App.vue --> 
<script setup lang="ts">import Myslot from "@/components/myslot.vue";
</script><template><div><my-slot> 我的身体 <template #body>身体</template><template v-slot:header>我的头部</template></my-slot></div>
</template>

动态插槽

<template><div>这里有很多插槽<div><slot name="mo_1">1</slot><slot name="mo_2">2</slot><slot name="mo_3">3</slot><slot name="mo_4">4</slot><slot name="mo_5">5</slot><slot name="mo_6">6</slot><slot name="mo_7">7</slot><slot name="mo_8">8</slot><slot name="mo_9">9</slot></div></div>
</template>
<script setup lang="ts">import syncModal from "@/components/syncModal.vue";import {computed,ref} from "vue";const name = ref(1)function click() {name.value++if (name.value === 10) {name.value = 1}}const slotName = computed(() => {return "mo_" + name.value})
</script>
<template><div><button @click="click">点我</button><syncModal><template #[slotName]>a</template></syncModal></div>
</template>

作用域插槽

具名插槽的作用域

<template><div><slot name="body" msg="这是消息" :age="12"></slot></div>
</template>
<msgSlot><template #body="data">这是插槽内部传递的数据:{{ data.msg }} age:{{ data.age }}</template>
</msgSlot>

默认插槽的作用域(和具名插槽写法不太一样)

<template><div><slot msg="这是消息" :age="12"></sLot></div>
</template>
<msgSlot v-slot="data">这是插槽内部传递的数据: {{ data.msg }} age:{{ data.age }}
</msgSlot>
<!-- 在有具名插槽情况下 -->
<template><div><my-slot><template #default="d">身体 {{ d }}</template><template #header="data">头部 {{ data }}</template></my-slot></div>
</template>

Vue

Vue概述

Vue 是渐进式JavaScript框架

  • Vue.js 自底向上增量开发的设计

  • Vue的核心库关注于视图

  • 渐进式:一步一步,不是将所有的东西都学完才能使用

  • 自底向上设计

  • Vue.js的核心是允许采用简洁式模板语法来声明的将数据渲染进DOM的系统

VueJQuery区别

数据驱动试图

  • jquery直接操作dom 到转变为操作数据

  • jQuery是使用选择器选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象

  • Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM

1、Vue基本语法

官方文档

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<!-- 在编辑器上下载vue插件即可有提示 -->
<!-- npm create vue@latest -->

插值表达式

使用{{ }}进行渲染data:{}中的变量

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">{{ message }}</div>
<script>const { createApp, ref } = VuecreateApp({setup() {const message = ref('Hello vue!')return {message}}}).mount('#app')
</script>
<script src="./vue.js"></scripts>
<div id="app">{{a}}{{dic.name}}{{List[0].name}}<div>{{ getInfo() }}</div>
</div>
<script>var vue = new Vue({el: '#app',  // vue挂载data:{a: 'huajiang',dic:{name:'杨小槿',age: 18,},List:[{name:'任小粟'},{name:'杨安京'},                ]},methods: {getInfo() { return 'Hello vue!';}}})
</script>
<!-- 控制台vue.a="sll" -->

2、绑定属性

v-text

渲染文本,和插值表达式类似,也是支持运算符的

<script src="./vue.js"></scripts>
<div id="app"><div v-text="msg"></div><div>{{ msg }}</div><div v-text="2 > 4 ? '成立': '不成立'"></div>
</div>
<script>var vue = new Vue({el: '#app',  // vue挂载data:{a: '天空一声巨响,老奴闪亮登场',msg: "嗨嗨嗨,来喽"},})
</script>

v-html

注意:v-html一般是用来渲染信任的文本,例如文章的详情内容等,最好不要用在用户提交的地方,容易造成XSS攻击

<script src="./vue.js"></scripts>
<div id="app"><div v-html="aDemo">{{aDemo}}</div>  <!-- v-html编译成html --><div v-text="aDemo">{{aDemo}}</div>  <!-- v-text直接输出文本 -->
</div>
<script>var vue = new Vue({el: '#app',  // vue挂载data:{a: 'huajiang',aDemo: '<a href="http://www.baidu.com" target="_blank">百度</a>'},})
</script>

v-bind (控制属性, 简写:)

属性上不能使用插值表达式({{}}

v-bind: 可以简写为 :

<script src="./vue.js"></scripts>
<div id="app"><div class="name" v-bind:title="a.name">姓名: {{a.name}}</div><img v-bind:src="src" alt=""><img :src="src" alt="">
</div>
<script>var vue = new Vue({el: '#app',  // vue挂载data: {a: {name: "杨小槿",age: 18,},src: 'https://profile-avatar.csdnimg.cn/392dc034291241239877635a77987f39_m0_65534674.jpg!1',}})
</script>

v-bind不仅可用于HTML存在的属性,还可以应用在自定义属性上

<p :id="'p' + '_01'" :data="msg" :还可以是中文="msg"></p>
<p id="p_01" data="haha" 还可以是中文="haha"></p>

vue所有的指令,都支持表达式

<div class="name" :title="'www'+a.split('.')[1]"><!-- var a = 1; 语句 -->{{ a.length === 0 ? '没有数据' : a }}    <!-- 表达式 -->-{{ a.split('.')[1] }}
</div>

3、条件渲染

v-if和v-else的普通使用

v-if中的布尔值为true,则渲染这个div

如果if不成立,则渲染else中的代码块

<script src="./vue.js"></script>
<div id="app"><div class="name" v-if="flag">{{ num }}</div><div id="if"><div v-if="num > 0.9">大于0.9的概率</div><div v-else>v-if不满足显示我</div></div>
</div>
<script>new Vue({el: '#app',data: {num: Math.random(), // 一个0-1之间的随机数字flag: false,}})
</script>

v-else-if多条件语句

<div id="v-else-if"><div v-if="num > 0.9">大于0.9的概率</div><div v-else-if="num > 0.6">大于0.6的概率</div><div v-else-if="num > 0.4">大于0.4的概率</div><div v-else-if="num > 0.2">大于0.2的概率</div><div v-else>所有条件都不成立</div>
</div>

v-show与v-if的区别

  • v-if如果是false,不会渲染

  • v-show如果是false,不会显示 style="display: none;"

<script src="./vue.js"></script>
<div id="app"><div class="name" v-show="flag">{{ num }}</div><!-- style="display: none;渲染之后隐藏了 -->
</div>
<script>new Vue({el: '#app',data: {flag: false,}})
</script>

4、列表渲染

主要分为遍历列表和遍历对象

遍历列表

key要唯一

<div id="app"><ul><li v-for="item in lis" :key="item">  <!-- key要唯一!!! -->{{ item }}</li><li v-for="(item, index) in lis" :key="item">  <!-- 带索引 -->{{ index }} -- {{ item }}</li></ul>
</div>
<script>var vue = new Vue({el: "#app",data:{lis: ['张三','王伟','张伟','王五',],}})
</script>

遍历对象

  • 一个参数,就是遍历对象的值

  • 二个参数,值和键

  • 三个参数,值,键,索引

<div id="app"><ul><li v-for="item in obj" :key="item">{{ item }}</li></ul><ul><li v-for="(item, key) in obj" :key="item">{{ key }}{{ item }}</li></ul><ul><li v-for="(item, key, index) in obj" :key="item">{{ index }}{{ key }}{{ item }}</li></ul>
</div>
<script>var vue = new Vue({el: "#app",data:{obj:{name: '张三',age: 21,addr: '北京市',},}})
</script>

5、Vue事件

v-on:或者@

事件

<div id="app"><div>{{ num }}</div><div><button v-on:click="add">点我 +</button><button @dblclick="num--">点我 -1</button>  <!-- dblclick双击鼠标 --></div>
</div>
<script>var vue = new Vue({el: "#app",data:{num: 1,},methods:{add(){this.num++;}}})
</script>

参数问题,可以通过传参进行参数传递

<div id="app"><div>{{ num }}<button v-on:click="add(10)">点我 +</button></div>
</div>
<script>var vue = new Vue({el: "#app",data:{num: 1,},methods:{add(number) {this.num += number}}})
</script>

默认参数,默认参数就是触发当前事件的事件对象

一定是v-on:click="add",只写一个函数名,而不是v-on:click="add()",这样获取不到事件对象

<div id="app"><div>{{ num }}<button id="add" class="add_cls" v-on:click="add">点我 +</button></div>
</div>
<script>var vue = new Vue({el: "#app",data:{num: 1,},methods:{add(event) {this.num++;// 触发当前事件的事件对象console.log(event)// 获取标签console.log(event.target)// 获取id,classconsole.log(event.target.id)console.log(event.target.className)}}})
</script>

如果有参数,想接收事件对象,使用$event进行传递

<script src="./vue.js"></script>
<div id="app"><div>{{ num }}<button id="add" class="add_cls" v-on:click="add(10, $event)">点我 +</button></div>
</div>
<script>var vue = new Vue({el: "#app",data:{num: 1,},methods:{add(number, event) {this.num += number// 触发当前事件的事件对象console.log(event)// 获取标签console.log(event.target)// 获取id,classconsole.log(event.target.id)console.log(event.target.className)}}})
</script>

6、图片轮播案例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>图片轮播</title><script src="./vue.js"></script></head><body><div id="app"><div><img :src="img_list[index]" alt=""></div><div><button @click="prevImag(index, img_list.length)">上一张</button><button @click="nextImag">下一张</button></div></div><script>var vue = new Vue({el: '#app', // vue挂载的位置,不能是bodydata: {index: 0,img_list: ['https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_1ac33.thumb.400_0.jpg','https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_48820.thumb.400_0.jpg','https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_e0b09.thumb.400_0.jpg','https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_efdaf.thumb.400_0.jpg','https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_6e9d5.thumb.400_0.jpg','https://c-ssl.dtstatic.com/uploads/blog/202210/05/20221005212142_c33fb.thumb.400_0.jpg',]},methods: {// 下一张nextImag() {// 让索引加1// 判断是不是最后一张,如果是就回到第一张if (this.index === this.img_list.length - 1) {this.index = 0return}this.index++},// 上一张prevImag(index, len){// 我希望把索引和列表长度传递进来if (index === 0) {this.index = len - 1return}this.index --}}})</script></body>
</html>

事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节

为了解决这个问题,Vue.jsv-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的

<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a><!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form><!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a><!-- 只有修饰符 -->
<form v-on:submit.prevent></form><!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div><!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!--阻止默认事件-->
<a href="http://www.baidu.com" @click.prevent="my_alert">杨小槿</a>
<script src=".vue.js"></script>
<div id="app"><a href="http://www.baidu.com" @click="my_alert">百度</a>
</div>
<script>new Vue({el: '#app',methods:{my_alert(e){console.log(e.target)console.log(e.preventDefault())  // event.preventDefault() vent.stopPropagation()alert("是否跳转")}}})
</script>
事件冒泡
<div class="parent" @click="log('外元素')"><div class="center" @click="log('中元素')"><div class="child" @click="log('里元素')"></div></div>
</div>
<!-- 点击里元素,输出里中外(这就是冒泡);点击中,输出中外 -->
<!-- 被父元素包裹的元素,点击事件发送后会逐级将事件向上传递 -->

img

<p>阻止事件冒泡</p>
<div class="parent" @click="log('外元素')"><div class="center" @click="log('中元素')"><div class="child" @click.stop="log('里元素')"></div></div>
</div>
<!-- 添加stop事件修饰符之后,点击里元素,会阻止事件继续向上传播 -->

键盘事件

@keydown   键盘按下
@keyup     键盘回弹

按下回车触发,支持组合键

9、v-model双向数据绑定

<input type="text" v-model="msg">
<input type="text" :value="msg">
...
date:{msg:"abcd",
}
<div id="app"><div><input type="text" v-model.lazy="msg">  <!-- .lazy事件修饰符,失焦后再改变 --><button @click="getMsg">获取</button><select v-model="selected"><!-- 变成多选<select v-model="selected" multiple>,然后把selected改成列表 --><option :value="item.value" :key="item.value" v-for="item in select_list">{{item.label}}</option></select></div>
</div>
<script>var vue = new Vue({el:'#app',data:{msg:"杨小槿",selected: 2,select_list:[{value: 1, label:'麻辣香锅'},{value: 2, label:'铁锅炖'},{value: 3, label:'烤肉'},{value: 4, label:'火锅'},]},methods:{getMsg(){console.log(this)}}})
</script>
<input type="text" v-model="msg" @keyup.enter.ctrl="get_msg('上')">
<input type="text" v-model="msg" @keyup.enter="get_msg('上')">

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

2.1.4新增
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

按键修饰符

<!-- 最常见的可能就是在一个输入框中,判断用户是否按下了回车键 -->
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<!-- 一些必要的按键名称 -->
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
<!-- 组合按键 -->
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>

7、计算属性

  • 调用的时候不用加括号(只是一个属性)

  • 可以监听属性变化,属性变化,计算属性重新执行

  • 有缓存(多个计算属性,只执行一次)

和methods的区别

属性变化,methods方法全部重新获取

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>计算属性</title><script src="../vue.js"></script>
</head>
<body>
<div id="app"><div>{{ name }}</div><div>{{ name.split('').reverse().join('') }}</div><div>{{ name.length === 5 ? '五言绝句' : '七言绝句' }}</div><div v-if="name.length === 5">五言绝句</div><div v-else-if="name.length === 7">七言绝句</div><div v-else>错了</div><!--  计算属性  --><div>{{ getName }}</div><div>{{ getName }}</div><div>{{ get_data_name() }}</div><div>{{ get_data_name() }}</div><button @click="getsub">点我</button><span>{{ num }}</span><button @click="set_name">计算属性</button>
</div>
<script>var vue = new Vue({el: '#app', // vue挂载的位置,不能是bodydata: {name: '床前明月光',num: 0},methods: {get_data_name() {console.log('属性方法')return this.name.split('').reverse().join('')},getsub(e) {this.num ++},set_name(){this.name += 'a'}},computed: {getName() {console.log('计算属性')return this.name.split('').reverse().join('')}}})
</script>
</body>
</html>

computed与watch,methods的区别

computed:有缓存(多个计算属性,只执行一次),节省了性能开销,计算属性不能传值

methods:可以放入函数,并且没有缓存

watch:监听,当数据发送变化时,才会触发,可以得到现在的值和过去的值,还可以监听路由变化,和属性同名

8、自定义过滤器

计算属性不能传值不好搞

<script src="./vue.js"></script>
<div id="app"><li v-for="item in student_list" :key="item.id">{{item.name|getLastChar }} -- {{ item.addr }}</li>
</div>
<script>var vue = new Vue({el: '#app',data: {student_list: [{name: '张三', addr: '北京市海淀区', id: 1 },{name: '李四', addr: '上海市浦东区', id: 2 },{name: '王五', addr: '广州市天河区', id: 3 }]},// 自定义过滤器filters:{// 截取最后一个字符getLastChar(item){return item.substr(item.length - 1, 1) // .substr是截取字符串的函数}}})
</script>

时间过滤器

img

<div id="app"><div>当前时间:{{ now|get_date }}</div><ul><li v-for="item in date_list" :key="item.id">id:{{ item.id }} 时间:{{ item.date|get_date }}</li></ul><div>时间过滤</div><ul><li v-for="item in date_list" :key="item.id">id:{{ item.id }} 时间:{{ item.date|time_to_filter }}</li></ul>
</div>
<script src="../vue.js"></script>
<script>function getDateDiff(datestamp) {var publishTime = datestamp / 1000,d_seconds,d_minutes,d_hours,d_days,timeNow = parseInt(new Date().getTime() / 1000),d,date = new Date(publishTime * 1000),Y = date.getFullYear(),M = date.getMonth() + 1,D = date.getDate(),H = date.getHours(),m = date.getMinutes(),s = date.getSeconds();//小于10的在前面补0if (M < 10) {M = '0' + M;}if (D < 10) {D = '0' + D;}if (H < 10) {H = '0' + H;}if (m < 10) {m = '0' + m;}if (s < 10) {s = '0' + s;}d = timeNow - publishTime;d_days = parseInt(d / 86400);d_hours = parseInt(d / 3600);d_minutes = parseInt(d / 60);d_seconds = parseInt(d);if (d_days > 0 && d_days < 30) {return d_days + '天前';} else if (d_days <= 0 && d_hours > 0) {return d_hours + '小时前';} else if (d_hours <= 0 && d_minutes > 0) {return d_minutes + '分钟前';} else if (d_seconds < 60) {if (d_seconds <= 0) {return '刚刚发表';} else {return d_seconds + '秒前';}} else if (d_days >= 30) {return Y + '-' + M + '-' + D + ' ' + H + ':' + m;}}var vue = new Vue({el: '#app',data: {now: '2021-12-8 22:01:11',date_list: [{id: 1, date: '2021-12-8 22:02:11'},{id: 2, date: '2021-12-6 22:02:21'},{id: 3, date: '2021-12-8 21:01:14'},{id: 4, date: '2021-12-5 20:12:11'},]},filters: {// 年-月-日get_date(date_str) {// date,传递的参数// 字符串转时间对象let date = new Date(date_str)return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`},time_to_filter(date_str) {// 字符串->对象->时间戳// 和当前时间做差,算出相差的时间(多少秒,多少分)// 字符串转时间对象->时间戳let datestamp = new Date(date_str).getTime()return getDateDiff(datestamp)}}})
</script>

参数问题

自定义过滤器也是可以接受参数,它的书写语法是

<script src="./vue.js"></script>
<div id="app"><li v-for="item in date_list" :key = "item.id" >id: {{ item.id }}时间: {{ item.date | time_to_filter('a', 'b') }} </li>
</div>
<script>var vue = new Vue({el: '#app',data: {date_list: [{id: 1, date: '2021-01-01 12:00:00'},{id: 2, date: '2021-01-02 13:00:00'},]},// 自定义过滤器filters: {time_to_filter(date_str, a, b) {// date_str  ->  '自身的值'// a  -> 'a'// b  -> 'b'return date_str}}})
</script>

过滤器方法的第一个参数就是调用者本身的值,第二个参数之后就是调用的实参,并且支持链式过滤器

<div>{{now|get_now|get_now1}}</div>

全局方法

需要将属性和方法挂载到Vue.prototype

Vue.prototype.$com = "全局变量"
let global_method = () => {return "全局方法"
}
function add() {return "全局 add 方法"
}
Vue.prototype.$global_method = global_method
Vue.prototype.$add = add

使用

<div>{{ $global_method() }}
</div>
<div>{{ $add() }}
</div>

全局过滤器

// 全局过滤器
let global_filter = (item) => {return item + '--global'
}
// 注册全局过滤器   (过滤器名称,方法)
Vue.filter('global_filter', global_filter)

使用全局过滤器

<div>{{ $com|global_filter }}
</div>

10、vue组件

内容共同使用,但是数据是相互隔离的 components

局部组件

<script src="./vue.js"></script>
<div id="app"><App></App>  <!--使用子组件-->
</div>
<script>// app 组件 html css jsconst App = {template: `<div><h3>我是app组件</h3><p>{{ msg }}</p><button @click="C">按一下改变msg</button></div>`,data() {return {msg: 'hello'}},methods: {C() {this.msg = 'world'}},created(){  // 只要有组件调用就会执行console.log(1)},}new Vue({el: '#app',data: {},components: {App  // 挂载子组件}})
</script>

全局组件

<div id="app"><App></App>
</div>
<script>Vue.component('Vheader', {  // component注册template: `<div><span>我是导航组件</span></div>`})Vue.component('Vsider', {data() {return {msg: '侧边栏'};},template: `<div><span>我是侧边栏的msg: {{ msg }}</span></div>`,})const Vbtn = {template: `<button>按钮</button>`}const App = {template: `<div><Vheader></Vheader><Vbtn></Vbtn><Vsider></Vsider><h3>我是app组件</h3><p>{{ msg }}</p><button @click="C">按钮</button></div>`,data() {return {msg: 'hello'}},components: {Vbtn},methods: {C() {this.msg = 'world'}}}new Vue({el: '#app',data: {},components: {App}})
</script>

11、组件通信

父传子 props

父传子:通过props来进行通信

1. 在自组件中声明props接收在父组件挂载的属性
2. 可以在自组件的template在任意使用
3, 在父组件绑定自定义的属性

props传入一个对象

// 例: props的值
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
props: {data: {type: String,  // 类型required: true,  // 必填项default: '张三'  // 如果没传值,那么这个默认值就是它}
}
<div id="app"><App></App>  <!--使用子组件-->
</div>
<script>Vue.component('Child', {   // 定义子组件template: `<div><h3>这是子组件</h3><h3> 222 {{ childData }} </h3></div>`,props: ['childData']  // 接收父组件传递的属性})const App = {   // 定义父组件data() {  // 父组件的数据return {msg: '111'}},template: `<div><Child :childData="msg"></Child><p>{{ msg }}</p></div>`,}new Vue({el: '#app',data: {},components: {App  // 注册父组件}})
</script>

created与mounted

created(){console.log(this.data, 1)
},
mounted(){console.log(this.data, 2)
}

子传父

1. 在父组件中,自组件上绑定自定义事件
2. 在自组件中,触发原生的事件,在事件函数通过this.$emit触发自定义的事件
<div id="app"><div> 父组件 {{num}} </div><div><my_header v-on:add2="parent_add"/></div>
</div>
<script>let my_header = {template:`<div><button @click="add1">父组件值+1</button></div>`,data(){return{}},methods:{add1(){this.$emit('add2', {msg: '来自子组件的数据'})}},}new Vue({el: '#app',data:{num:10},components:{my_header},methods:{parent_add(data){console.log(data)this.num += 1}}})
</script>

平行组件

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>平行组件</title><script src="./vue.js"></script><style>body {margin: 0;}#app {display: flex;}#app > div {width: 50%;height: 200px;display: flex;justify-content: center;align-items: center;}#gouwuc {background-color: #3a8ee6;}#get {background-color: #b3d9d9;}</style></head><body><div id="app"><App1 id="gouwuc"></App1>  <!--使用子组件--><App2 id="get"></App2>  <!--使用子组件--></div><script>let Bus = new Vue()let App1 = {data() {return {num: 100}},template:`<div>购物车 商品总数{{ num }}</div>`,mounted(){Bus.$on('add2', (data)=>{this.num ++})}}let App2 = {template: `<div><button @click="add1">加入购物车</button></div>`,data() {return {num: 100}},methods: {add1() {Bus.$emit('add2', {msg: '你的好兄弟又下单啦'})}},}new Vue({el: '#app',data: {},components: {App1,App2,}})</script></body>
</html>

多次嵌套取值

1. provide  提供变量  函数(){return{}},
2. inject  接收变量 inject: [],

12、vue插槽

匿名插槽

修改已经写好的组件

在模板中把想要替换的东西放在<slot>标签中,这就是一个占位符

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>杨小槿</title><script src="./vue.js"></script><style> body{margin: 0;}#header{display: flex;height: 60px;}#header>div{width: 50%;display: flex;align-items: center;height: 100%;}</style></head><body><div id="app"> <my_header>首页</my_header><!-- <my_header>111</my_header> --><!-- 这样就会将标签中的内容去代替slot中的内容 --></div><script>let my_header = {data() {return {}},template: `<div id="header"><div class="left"><slot>左部分</slot></div><div class="right"><slot>右部分</slot><p>如果slot都没有名字,那么如果有多个slot,就会全部进行替换</p></div></div>`}   new Vue({el: '#app',components: {my_header}})</script></body>
</html>

具名插槽

如果你的模板中需要有多个地方被替换,那么匿名插槽就不适用

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>杨小槿</title><script src="./vue.js"></script><style> body{margin: 0;}#header{display: flex;height: 60px;}#header>div{width: 50%;display: flex;align-items: center;height: 100%;}</style></head><body><div id="app"> <my_header><template v-slot:left>左左左左左</template><!-- v-slot:  可以简写为  # --><template v-slot:right>右右右右右</template></my_heade></div><script>let my_header = {data() {return {}},template: `<div id="header"><div class="left"><slot name="left">左部分</slot></div><div class="right"><slot name="right">右部分</slot><!--若有多个slot,并且都没名字,那么就会全部进行替换--></div></div>`}   new Vue({el: '#app',components: {my_header}})</script></body>
</html>
<div id="app"> <my_header><template v-slot:left>左左左左左</template><!-- v-slot:  可以简写为  # --><template #right>右右右右右</template></my_heade>
</div>

我们在替换的时候,是可以写任意标签的,也就是说,在替换的时候,你也可以将组件写入插槽中

<div id="app"> <my_header><template v-slot:left>左左左左左</template><!-- v-slot:  可以简写为  # --><template v-slot:right>右右右右右</template><child></child></my_heade>
</div>
<script>let child = {data(){return {}},template: `<li>子组件</li>`}Vue.component('child', child)let my_header = {data() {return {user: {name: "杨小槿",age: 18,}}},template: `<div id="header"><div class="left"><slot name="left">左部分</slot></div><div class="right"><slot name="right">{{ user.name }}</slot><!--若有多个slot,并且都没名字,那么就会全部进行替换--></div></div>`}   new Vue({el: '#app',components: {my_header}})
</script>

作用域插槽

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>杨小槿</title><script src="./vue.js"></script><style> body{margin: 0;}#header{display: flex;height: 60px;}#header>div{width: 50%;display: flex;align-items: center;height: 100%;}</style></head><body><div id="app"> <my_header><template v-slot:left>左左左左左</template><!-- v-slot:  可以简写为  # --><template v-slot:right="slotProps">{{ slotProps.user.age }}</template></my_heade></div><script>let my_header = {data() {return {user: {name: "杨小槿",age: 18,}}},template: `<div id="header"><div class="left"><slot name="left">左部分</slot></div><div class="right"><slot :user="user" name="right">{{ user.name }}</slot><!--若有多个slot,并且都没名字,那么就会全部进行替换--></div></div>`}   new Vue({el: '#app',data: {},components: {my_header}})</script></body>
</html>

在子组件中,我在插槽里面显示的是user的xin,如果我想让它显示user的name应该怎么做呢

如果我们直接在父组件调用的时候这样写

<base_layout>{{ user.name }}
</base_layout>

这是错误的写法,因为我们的user是被定义再自组件中的,在父组件中就无法使用这个user,所以就会报错啦

那么我们就应该将这个user对象传递给父组件

在子组件中

<slot :user="user">{{ user.xin }}</slot>

通过动态属性的方式将user传递给父组件

在父组件中

<base_layout><template v-slot:default="slotProps">{{ slotProps.user.name }}</template>
</base_layout>

接收传递来的user即可

slotProps可以是你自己定义的名字,它里面存储的是这样的

{ "user": { "name": "枫枫", "xin": "知道" } }

所以我们将slotProps中的user中的name传递给子组件,就可以做到数据动态替换

如果你的组件中,有且只有一个默认插槽,那么在替换的时候,是可以这么做的

<base_layout v-slot:default="slotProps">{{ slotProps }}
</base_layout>

13、自定义指令

动态组件

<component>元素是vue里面的一个内置组件。 在里面使用 v-bind: is,可以实现动态组件的效果

自定义指令

前面使用的v-if, v-show,以及v-for这些都是Vue为我们提供的内置指令

当然,我们也可以自己自定义一个指令

局部自定义指令

directives: {focus: {// 指令的定义// 使用这个指令就会聚焦在输入框中inserted: function (el) {el.focus()}}
}

使用

<input type="text" v-focus>

在focus中有几个钩子函数,需要了解

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

绑定方法到this

Vue.prototype.meta_ = () => {console.log(1)
}

在created生命周期中不能使用

可以在mounted方法中使用

14、vue国际化

安装

npm install vue-i18n@9

基本使用

在src目录下创建lang目录

在此目录下创建对应语言的ts文件,如:

zh.ts

en.ts

kor.ts 韩文

jp.ts日文

zh.ts示例

export default {"首页": "首页","新闻": "新闻","产品": "产品",index: "首页"
};

en.ts

// en.js
export default {"首页": "Index","新闻": "News","产品": "Product",index: "Index"
}

然后新建一个index.tslang目录下

import {createI18n } from 'vue-i18n'
import zh from "@/lang/zh";
import en from "@/lang/en";const i18n = createI18n({locale: "zh", // 默认是中文legacy: false, // 解决报错的messages: {"zh": zh,"en": en,}
})export default i18n

然后在main.ts中进行注册

import {createApp} from 'vue'
import App from './App.vue'
import i18n from "@/lang/index"const app = createApp(App)
app.use(i18n)
app.mount('#app')

在vue的模板中使用

<template><main><div><span>{{ $t("首页") }}</span><span>{{ $t("新闻") }}</span><span>{{ $t("产品") }}</span></div></main><header><button @click="setLang('zh')">中文</button><button @click="setLang('en')">英文</button></header>
</template>
<script setup lang="ts">import {useI18n} from 'vue-i18n'const {t} = useI18n();console.log(t('index'))function setLang(lang:string){locale.value = lang}
</script>

如果$t警告的话,就在env.d.ts里面加上

/// <reference types="vite/client" />
declare function $t()

翻译数据从后端来

后端

npm i axios
npm i mockjs
npm i @types/mockjs

准备两个接口

一个是展示有哪些语言的

一个是有对应语言的字典文件

export function langList(): Promise<string[]> {return useAxios.get("/api/langs")
}
export function langDetail(lang: string): Promise<object> {return useAxios.get("/api/langs/detail", {params: {lang}})
}

mock

import {mock} from "mockjs";
mock(/api\/langs\/detail/, function (options) {if (options.url.includes("zh")) {return {"首页": "首页","新闻": "新闻","产品": "产品",index: "首页"}}if (options.url.includes("en")) {return {"首页": "Index","新闻": "News","产品": "Product",index: "Index"}}
})
mock(/api\/langs/, ["zh", "en"])

页面语言切换

<template>
<header><button @click="setLang(item)" v-for="item in langs">{{ item }}</button></header>
<main><span>{{ $t("首页") }}</span><span>{{ $t("新闻") }}</span><span>{{ $t("产品") }}</span></main>
</template><script setup lang="ts">import {useI18n} from 'vue-i18n'import {langList, langDetail} from "@/api";import {ref} from "vue";const {locale, t, messages} = useI18n();const langs = ref([])async function getData() {langs.value = await langList()}getData()async function setLang(lang: string) {messages.value[lang] = await langDetail(lang)console.log(messages.value)locale.value = lang; // 切换语言}
</script>

参考文档

官网

Not available in legacy mode

在ts中使用

配置i18n国际化

相关文章:

Vue3、vue学习笔记

<!-- Vue3 --> 1、Vue项目搭建 npm init vuelatest cd 文件目录 npm i npm run dev // npm run _ 这个在package.json中查看scripts /* vue_study\.vscode可删 // vue_study\src\components也可删除(基本语法&#xff0c;不使用组件) */ // vue_study\.vscode\lau…...

用OpenCV写个视频播放器可还行?(C++版)

引言 提到OpenCV&#xff0c;大家首先想到的可能是图像处理、目标检测&#xff0c;但你是否想过——用OpenCV实现一个带进度条、倍速播放、暂停功能的视频播放器&#xff1f;本文将通过一个实战项目&#xff0c;带你深入掌握OpenCV的视频处理能力&#xff0c;并解锁以下功能&a…...

clion+arm-cm3+MSYS-mingw +jlink配置用于嵌入式开发

0.前言 正文可以跳过这段 初识clion&#xff0c;应该是2015年首次发布的时候&#xff0c; 那会还是大三&#xff0c;被一则推介广告吸引到&#xff0c;当时还在用vs studio&#xff0c;但是就喜欢鼓捣新工具&#xff0c;然后下载安装试用了clion&#xff0c;但是当时对cmake规…...

物联网-IoTivity:开源的物联网框架

IoTivity 是一个开源的物联网(IoT)框架,旨在为物联网设备提供互操作性、安全性和可扩展性。它由 Open Connectivity Foundation (OCF) 主导开发,遵循 OCF 的标准,致力于实现设备之间的无缝连接和通信。IoTivity 提供了一个统一的框架,支持设备发现、数据交换、设备管理和…...

Acrobat DC v25.001 最新专业版已破,像word一样编辑PDF!

在数字化时代&#xff0c;PDF文件以其稳定性和通用性成为了文档交流和存储的热门选择。无论是阅读、编辑、转换还是转曲&#xff0c;大家对PDF文件的操作需求日益增加。因此&#xff0c;一款出色的PDF处理软件不仅要满足多样化的需求&#xff0c;还要通过简洁的界面和强大的功能…...

【c++】模板进阶

在前面我们学习了模板的基础用法【c】 模板初阶-CSDN博客初步认识了函数模板和类模板&#xff0c;接下来让我们看看模板还有哪些进阶的应用。 非类型模板参数 之前我们用到的模板全都使用了类型参数 类型参数&#xff1a;表示某种数据类型&#xff08;如 int、double、自定义…...

IntelliJ IDEA 2021版创建springboot项目的五种方式

第一种方式&#xff0c;通过https://start.spring.io作为spring Initializr的url来创建项目。 第二种方式&#xff0c;通过https://start.spring.io官网来直接创建springboot项目压缩包&#xff0c;然后导入至我们的idea中。 点击generate后&#xff0c;即可生成压缩包&#xf…...

数字信号处理之信号功率谱计算welch方法(分段加窗平均周期图)、Bartlett方法(周期图)(Python)

welch方法原理说明 welch方法[1]通过将数据划分为重叠的段&#xff0c;计算每个段的进行修改(加窗)后的周期图&#xff0c;然后对所有段的周期图求和进行平均&#xff0c;得到最终的功率谱密度。 Python和Matlab中均存在welch函数。welch函数通过配置noverlap为0&#xff0c;可…...

【面试】Java 基础

基础 1、Java 中几种基本数据类型什么&#xff0c;各自占用多少字节2、基本数据同包装类的区别3、Java 基本类型的参数传递和引用类型的参数传递有啥区别4、隐式类型转换和显式类型转换5、switch 语句表达式结果的类型6、数组的扩容方式7、面向对象三大特征8、静态变量和成员变…...

【工具使用】IDEA 社区版如何创建 Spring Boot 项目(详细教程)

IDEA 社区版如何创建 Spring Boot 项目&#xff08;详细教程&#xff09; Spring Boot 以其简洁、高效的特性&#xff0c;成为 Java 开发的主流框架之一。虽然 IntelliJ IDEA 专业版提供了Spring Boot 项目向导&#xff0c;但 社区版&#xff08;Community Edition&#xff09…...

CTFHub-FastCGI协议/Redis协议

将木马进行base64编码 <?php eval($_GET[cmd]);?> 打开kali虚拟机&#xff0c;使用虚拟机中Gopherus-master工具 Gopherus-master工具安装 git clone https://github.com/tarunkant/Gopherus.git 进入工具目录 cd Gopherus 使用工具 python2 "位置" --expl…...

【Python字符串】\n是什么?它与raw字符串、多行字符串的运用有什么关系?

李升伟 整理 在Python中&#xff0c;\n 是换行符&#xff0c;用于在字符串中表示新的一行。当你在字符串中使用 \n 时&#xff0c;Python 会在该位置插入一个换行符&#xff0c;使得输出在 \n 处换行。 1. 普通字符串中的 \n 在普通字符串中&#xff0c;\n 会被解释为换行符…...

Linux 配置静态 IP

一、简介 在 Linux CentOS 系统中默认动态分配 IP 地址&#xff0c;每次启动虚拟机服务都是不一样的 IP&#xff0c;因此要配置静态 IP 地址避免每次都发生变化&#xff0c;下面将介绍配置静态 IP 的详细步骤。 首先先理解一下动态 IP 和静态 IP 的概念&#xff1a; 动态 IP…...

git lfs使用方法指南【在github保存100M以上大文件】

为了在 GitHub 仓库中存储超过 100MB 的大文件并避免推送失败&#xff0c;使用 Git LFS&#xff08;Large File Storage&#xff09; 是最佳解决方案。以下是详细步骤&#xff1a; 一、安装 Git LFS 下载并安装 Git LFS&#xff1a; 访问 Git LFS 官网 下载对应系统的安装包。或…...

【Linux】初识线程

目录 一、什么是线程&#xff1a; 重定义线程和进程&#xff1a; 执行流&#xff1a; Linux中线程的实现方案&#xff1a; 二、再谈进程地址空间 三、小结&#xff1a; 1、概念&#xff1a; 2、进程与线程的关系&#xff1a; 3、线程优点&#xff1a; 4、线程…...

【Linux学习笔记】Linux基本指令分析和权限的概念

【Linux学习笔记】Linux基本指令分析和权限的概念 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 文章目录 【Linux学习笔记】Linux基本指令分析和权限的概念前言一. 指令的分析1.1 alias 指令1.2 grep 指令1.3 zip/unzip 指…...

uniapp登录用户名在其他页面都能响应

使用全局变量 1、在APP.vue中定义一个全局变量&#xff0c;然后在需要的地方引用它&#xff1b; <script>export default {onLaunch: function() {console.log(App Launch)this.globalData { userInfo: {} };},onShow: function() {console.log(App Show)},onHide: fu…...

ESP8266 入门(第 2 部分):使用 AT 命令

使用 AT 命令对 WiFi 收发器ESP8266编程 本教程是上一个教程 ESP8266 入门(第 1 部分)的延续。因此,简单回顾一下,在之前的教程中,我们介绍了 ESP 模块,并学习了一些基础知识。我们还使用 FTDI 串行适配器模块制作了一个开发板,该模块可以很容易地用于使用 AT 命令和 A…...

介绍一下Qt 中的QSizePolicy 布局策略

在 Qt 中&#xff0c;QSizePolicy 类用于描述一个控件在布局中如何分配空间&#xff0c;它定义了控件在水平和垂直方向上对空间的需求和响应策略。以下是对 QSizePolicy 策略的详细介绍&#xff1a; 基本概念 QSizePolicy 包含两个主要的属性&#xff1a;Policy&#xff08;策…...

从ETL到数仓分层:大数据处理的“金字塔”构建之道

在当今数据驱动的时代&#xff0c;大数据处理已成为企业决策和业务优化的核心。而ETL&#xff08;Extract, Transform, Load&#xff09;作为数据处理的基石&#xff0c;其背后的数仓分层理念更是决定了数据处理的效率与质量。本文将深入探讨ETL工作中的数仓分层理念&#xff0…...

springBoot集成声明式和编程式事务的方式

一、声明式事务 前提集成了mybatisplus插件 1、pom依赖 <dependencies><!-- MyBatis-Plus 启动器 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.4&l…...

前端实现版本更新自动检测✅

&#x1f916; 作者简介&#xff1a;水煮白菜王&#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧和知识归纳总结✍。 感谢支持&#x1f495;&#x1f495;&a…...

Python零基础学习第三天:函数与数据结构

一、函数基础 函数是什么&#xff1f; 想象你每天都要重复做同一件事&#xff0c;比如泡咖啡。函数就像你写好的泡咖啡步骤说明书&#xff0c;每次需要时直接按步骤执行&#xff0c;不用重新想流程。 # 定义泡咖啡的函数 def make_coffee(sugar1): # 默认加1勺糖 print("…...

深入了解Linux —— 调试程序

前言 我们已经学习了linux下许多的工具&#xff0c;vim、gcc、make/makefile等&#xff1b; 已经能够在linux写代码&#xff0c;并且进行编译运行&#xff0c;让程序在linux下跑起来。 但是&#xff0c;如果我们在写代码的时候遇见了错误&#xff1b;但是我们并不知道错误在哪&…...

解决VScode 连接不上问题

问题 &#xff1a;VScode 连接不上 解决方案&#xff1a; 1、手动杀死VS Code服务器进程&#xff0c;然后重新尝试登录 打开xshell &#xff0c;远程连接服务器 &#xff0c;查看vscode的进程 &#xff0c;然后全部杀掉 [cxqiZwz9fjj2ssnshikw14avaZ ~]$ ps ajx | grep vsc…...

行式数据库与列式数据库区别

列式数据库&#xff08;Columnar Database&#xff09;和行式数据库&#xff08;Row-based Database&#xff09;是两种不同的数据存储和检索方式&#xff0c;它们在数据组织、存储结构和适用场景上有显著区别。以下是对两者的详细对比&#xff1a; 1. 数据存储方式 行式数据库…...

如何将本地已有的仓库上传到gitee (使用UGit)

1、登录Gitee。 2、点击个人头像旁边的加号&#xff0c;选择新建仓库&#xff1a; 3、填写仓库相关信息 4、复制Gitee仓库的地址 5、绑定我们的本地仓库与远程仓库 6、将本地仓库发布&#xff08;推送&#xff09;到远程仓库&#xff1a; 注意到此处报错&#xff…...

FIWARE:开源的物联网平台,支持设备虚拟化和数据管理

FIWARE 是一个开源的物联网(IoT)平台,旨在为物联网应用提供强大的数据管理和设备虚拟化功能。FIWARE 提供了一系列通用的 API 和组件,支持设备管理、数据采集、数据处理、数据共享和安全通信等功能,使得开发者能够快速构建和扩展物联网解决方案。以下是 FIWARE 的核心功能…...

RISC-V汇编学习(三)—— RV指令集

有了前两节对于RISC-V汇编、寄存器、汇编语法等的认识&#xff0c;本节开始介绍RISC-V指令集和伪指令。 前面说了RISC-V的模块化特点&#xff0c;是以RV32I为作为ISA的核心模块&#xff0c;其他都是要基于此为基础&#xff0c;可以这样认为&#xff1a;RISC-V ISA 基本整数指…...

【Linux】冯诺依曼体系与操作系统理解

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、冯诺依曼体系结构 二、操作系统 1. 操作系统的概念 2. 操作系统存在的意义 3. 操作系统的管理方式 4. 补充&#xff1a;理解系统调用…...

Android15使用FFmpeg解码并播放MP4视频完整示例

效果: 1.编译FFmpeg库: 下载FFmpeg-kit的源码并编译生成安装平台库 2.复制生成的FFmpeg库so文件与包含目录到自己的Android下 如果没有prebuiltLibs目录,创建一个,然后复制 包含目录只复制arm64-v8a下...

音视频入门基础:RTP专题(16)——RTP封装音频时,音频的有效载荷结构

一、引言 《RFC 3640》和《RFC 6416》分别定义了两种对MPEG-4流的RTP封包方式&#xff0c;这两个文档都可以从RFC官网下载&#xff1a; RFC Editor 本文主要对《RFC 3640》中的音频打包方式进行简介。《RFC 3640》总共有43页&#xff0c;本文下面所说的“页数”是指在pdf阅读…...

3.3.2 Proteus第一个仿真图

文章目录 文章介绍0 效果图1 新建“点灯”项目2 添加元器件3 元器件布局接线4 补充 文章介绍 本文介绍&#xff1a;使用Proteus仿真软件画第一个仿真图 0 效果图 1 新建“点灯”项目 修改项目名称和路径&#xff0c;之后一直点“下一步”直到完成 2 添加元器件 点击元…...

MySQL创建数据库和表,插入四大名著中的人物

一、登录数据库并创建数据库db_ck 二、创建表t_hero 表属性包括&#xff08;id&#xff0c;name&#xff0c;nickname&#xff0c;age&#xff0c;gender&#xff0c;address&#xff0c;weapon&#xff0c;types&#xff09; mysql> create table t_hero(-> id int,-…...

matlab和FPGA联合仿真时读写.txt文件数据的方法

在FPGA开发过程中&#xff0c;往往需要将MATLAB生成的数据作为原始激励灌入FPGA进行仿真。为了验证FPGA计算是否正确&#xff0c;又需要将FPGA计算结果导入MATLAB绘图与MATLAB计算结果对比。 下面是MATLAB“写.txt”、“读.txt”&#xff0c;Verilog“读.txt”、“写.txt”的代…...

C++修炼之路:初识C++

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞&#xff0c;关注&#xff01; 引言 …...

ACE协议学习1

在多核系统或复杂SoC&#xff08;System on Chip&#xff09;中&#xff0c;不同处理器核心或IP&#xff08;Intellectual Property&#xff09;模块之间需要保持数据的一致性。常用的是ACE协议or CHI。 先对ACE协议进行学习 ACE协议&#xff08;Advanced Microcontroller Bu…...

通俗易懂的介绍LLM大模型技术常用专业名词(通用版)

1. 神经网络 (Neural Network) 解释: 一种模拟人脑神经元结构的计算模型&#xff0c;用于处理复杂的数据模式。 示例: 图像识别中的卷积神经网络&#xff08;CNN&#xff09;。 2. 深度学习 (Deep Learning) 解释: 基于多层神经网络的机器学习方法&#xff0c;能够自动提取数…...

深度学习环境安装

Anaconda 3.0 下载地址 Download Success | Anaconda CUDA 下载地址 cuda_12.4.0 https://developer.nvidia.com/cuda-12-4-0-download-archive?target_osWindows&target_archx86_64&target_version11&target_typeexe_local pytorch 下载地址 &#xff08;2…...

【哇! C++】类和对象(五) - 赋值运算符重载

目录 ​编辑 一、运算符重载 1.1 运算符重载概念 1.2 全局运算符重载 1.3 运算符重载为成员函数 二、赋值运算符重载的特性 2.1 赋值运算符重载需要注意的点 2.2 赋值运算符重载格式 2.2.1 传值返回 2.2.2 传引用返回 2.2.3 检查自己给自己赋值 三、赋值运算符重载的…...

【时序图】1.StarUML绿化

1)下载地址 官网: StarUML 如下: 2)绿化 step1:用管理员打开cmd&#xff0c;执行如下 npm install -g asar cd C:\Program Files\StarUML\resources //进入到StarUML的默认安装目录下面 asar extract app.asar app //反编译软件step2:把resources下的app文件夹拷贝出来到…...

mysql练习

创建数据库db_ck&#xff0c;再创建表t_hero&#xff0c;将四大名著中的主要人物都插入这个表中&#xff0c;将实现过程中sql提交上上来 1、创建数据库db_ck mysql> create database db_ck; 2、创建表t_hero mysql> use db_ck Database changed mysql> create table …...

数据结构(队列)

数据结构&#xff08;队列&#xff09; 什么是队列&#xff1f; 队列和栈类似&#xff0c;也是一类特殊的线性表。特殊之处也是在于操作上。队列&#xff1a;只允许在一端进行插入数据操作&#xff08;入队&#xff09;&#xff0c;在另一端进行删除数据操作&#xff08;出队&…...

fps项目二次总结

文章目录 角色角色蓝图动画蓝图角色蓝图与动画蓝图间的通信动画蓝图绑定在网格体上 其他蓝图角色蓝图与其他蓝图的通信通信详解单向通信&#xff1a;A向B与B向A互不相通A向B发送消息A&#xff1a;发起方&#xff1a;即调用方B&#xff1a;接收方&#xff1a;即提供方&#xff1…...

VTK笔记- 3D Widget类 vtkSplineWidget 样条部件

vtk3DWidget vtk3DWidget是用于3D交互观察器的基类&#xff0c;也就是各种3D小部件类的基类&#xff0c;主要是在三维渲染场景中生成一个可以用于控制数据的可视化实体&#xff0c;比如点&#xff0c;线段&#xff08;曲线&#xff09;、平面、球体、包围盒&#xff08;线框&am…...

文心一言:中国大模型时代的破局者与探路者

2023年&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;的浪潮席卷全球&#xff0c;而百度推出的“文心一言”&#xff08;ERNIE Bot&#xff09;作为中国AI领域的代表性产品&#xff0c;迅速成为行业焦点。这款基于百度自主研发的“文心大模型”打造的对话式AI工具&am…...

【芯片验证】verificationguide上的36道UVM面试题

跟上一篇一样,verificationguide上的36到UVM面试题,通义回答ds判卷。 1. What is uvm_transaction, uvm_seq_item, uvm_object, uvm_component? uvm_transaction、uvm_seq_item、uvm_object、uvm_component是什么? uvm_transaction是UVM中所有事务的基础类,用于表示仿真…...

操作系统控制台-健康守护我们的系统

引言基本准备体验功能健康守护系统诊断 收获提升结语 引言 阿里云操作系统控制平台作为新一代云端服务器中枢平台&#xff0c;通过创新交互模式重构主机管理体验。操作系统控制台提供了一系列管理功能&#xff0c;包括运维监控、智能助手、扩展插件管理以及订阅服务等。用户可以…...

基于策略模式的智能提示语生成器设计与实现——以Tkinter GUI开发为例

基于策略模式的智能提示语生成器设计与实现——以Tkinter GUI开发为例 一、引言&#xff1a;智能化时代的提示工程工具 在人工智能技术广泛应用的时代背景下&#xff0c;如何与AI模型进行有效交互已成为关键技能。本文介绍的"AI任务需求与提示语策略生成器"正是基于…...

【打卡d1】算法模拟类

题目1 题目描述: 某百货公司为了促销&#xff0c;采用购物打折的优惠方法&#xff0c;每位顾客一次购物:在1000元以上者&#xff0c;按 9.5 折优惠;在2000以上者&#xff0c;按9折优惠;在3000以上者&#xff0c;按8.5 折优惠;在5000 以上者&#xff0c;按8折优惠;编写程序&…...