vue3 基础

创建一个Vue应用

确保已安装最新版本的 Node.js

npm create vue@latest

cd  <your-project-name>

npm install

npm run dev

// 打包

npm run build

应用实例

每一个Vue应用都是通过createApp 函数创建一个新的 应用实例

import { createApp } from 'vue'

// 从一个单文件组件中导入根组件
import App from './App.vue'

const app = createApp(App)

* 传入 createApp 的对象实际是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。

挂载应用

应用实例必须在调用 .mount() 方法后才会渲染出来。该方法接收一个“容器参数”,可以是一个实际的DOM元素或者一个 CSS 选择器字符串

<div id="app"></div>

app.mount('#app)

* 应用根组件的内容将会被渲染在容器元素里面,容器元素自己将不会被视为应用的一部分

应用配置

注册组件

app.component('TodoDeleteButton',TodoDeleteButton)

* 这使得TodoDeleteButton 在应用的任何地方都可用。

多个应用实例

createApp  API 允许你在同一个页面中创建多个共存的Vue应用,每个应用都有自己的用于配置和全局资源的作用域

const app1 = createApp({

})

app1.mount('#container-1')

const app2 = createApp({

})

app2.mount('#container-2')

模板语法

1.文本插值 使用 双大括号 {{}}   html 插入 使用 v-html
<span>Message: {{msg}}</span>

<p>Using v-html directive: <span v-html="rawHtml"></span></p>
2.Attribute 响应式绑定数据
<div :id="id"></div>

// 简写  请注意,这是一个只在 Vue 3.4 及以上版本中可用
<div :id></div>

// 布尔类型
<button :disabled="isButtonDisabled">Button</button>
3.动态绑定多个值 
const objectOfAttrs = {
    id:'container',
    class:'wrapper'
}

//通过不带参数的 v-bind ,可将它们绑定到单个元素上
<div v-bind="objectOfAttrs"></div>
4.使用JavaScript 表达式
{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>
5.动态参数名
<a v-bind:[attributeName]="url"> ... </a>

//简写
<a :[attributeName]="url"> ... </a>

//绑定事件
<a @[eventName]="doSomething"></a>
6.修饰符 Modifiers

修饰符是以 点 开头的特殊后缀,表明指令需要以一些特殊方式绑定。如  .prevent  修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault();

<form @submit.prevent="onSubmit"></form>

声明响应式状态

ref( ) 接受参数,设为默认值,并将其包裹在一个带有  .value  的属性的ref 对象中返回

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }}
  </button>
</template>

* 当你在模板中使用一个ref,然后改变这个ref的值时,Vue会自动检测到这个变化,并且相应地更新DOM。这是通过一个基于依赖追踪的响应式系统实现的。当一个组件首次渲染时,Vue会追踪在渲染过程中使用的每一个ref 。然后当一个 ref 被修改时,它会触发追踪它的组件一次重新渲染。

reactive() 与将内部值包装在特殊对象中的ref 不同, reactive()  将使对象本身具有响应性

1.有限的值类型:只能用于对象类型。不能持有如 string 、number 、 boolean 这样的原始类型

2.不能替换整个对象

3.对解构操作不友好:当将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,将丢失响应性链接

const state = reactive({count:0})

// 当解构时,count 已经与 state.count 断开连接
let {count} = state;
// 不会影响原始的 state
count++

DOM 更新时机

要等待 DOM 更新完成后再执行额外的代码,可以使用 nextTick() 全局 API:

import {nextTick} from 'vue'

asyncfunction increment() {
    count.value++
    await nextTick()
    // 现在DOM 已经更新了
}

组合式 API  (Composition API)与  <script setup>

<script setup>
import {ref, onMounted } from 'vue
const count = ref(0)
function increment(){
    count.value++
}

onMount(()=>{
    console.log(`打印 ${count.vaue}`)
})
</script>

计算属性

计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 author.books 不改变,无论多少次访问 booksLength都会立即返回先前的计算结果,而不用重复执行 getter 函数。

<script>
import {reactive, computed} from 'vue'

const author = reactive({
    name:'Jocon',
    books:['aa','bb','cc']
    
})

// 一个计算属性ref
const booksLength = computed(()=>{
    return author.books.length >0?'Yes':'No'
})
// booksLength.value  访问计算结果

</script>

<template>
    <p>是否借书?</p>
    <p>{{booksLength}}</p>
</template>

可写计算属性

计算属性默认是只读的。可以通过同时提供 getter 和 setter 来创建:

<script setup>
import {ref,reactive} from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
    //getter
    get() {
        return firstName.value + ' ' + lastName.value
    },
    //setter
    set(newValue){
        [firstName.value, lastName.value] = newValue.split(' ')
    }

})
</script>

现在当你再运行 fullName.value = 'John Doe' 时,setter 会被调用而 firstName 和 lastName 会随之更新。

Class 与 Style 绑定

<div :class="{active:isActive,'text-danger': hasError}"></div>

const isActive = ref(true)
const hasError = ref(false)

//渲染结果
<div class="active"></div>


// 绑定对象
const classObject = reactive({
    active:true,
    'text-danger':false
})
<div :class="classObject"></div>
<div class="active"></div>

// 绑定计算属性
const isActive = ref(true)
const error = ref(null)

const classObject = computed(() => ({
  active: isActive.value && !error.value,
  'text-danger': error.value && error.value.type === 'fatal'
}))
<div :class="classObject"></div>

//绑定数组
const activeClass = ref('active')
const errorClass = ref('text-danger')

<div :class="[activeClass, errorClass]"></div>

<div :class="[isActive ? activeClass : '', errorClass]"></div>

<div :class="[{ active: isActive }, errorClass]"></div>

组件上使用,只有一个根元素的组件这些 class 会被添加到根元素上并与该元素上已有的 class 合并,如果你的组件有多个根元素,你将需要指定哪个根元素来接收这个 class。你可以通过组件的 $attrs 属性来实现指定:

<p :class="$attrs.calss">Hi !</p>
<span>This is a child component</span>

<MyComponent class="baz" />

//渲染如下
<p class="baz">Hi!</p>
<span>This is a child component</span>

绑定内联样式

const activeColor = ref('red')
const fontSize = ref(30)

<div :style="{color:activeColor ,fontSize:fontSize+'px}"></div>


const styleObject = reactive({
  color: 'red',
  fontSize: '13px'
})
<div :style="styleObject"></div>

条件渲染

v-if  元素是否被渲染

v-show 会在DOM渲染中保留该元素;v-show 仅切换了该元素上display css属性

v-show 不支持在 template 元素上使用

列表渲染 v-for

const items = ref([{ message: 'Foo' }, { message: 'Bar' }])

<li v-for="(item, index) in items">
  {{ index }} - {{ item.message }}
</li>

// 变量名使用 解构
<li v-for="({message},index) in items">
    {{ index }} - {{ message }}
</li>

* 多层v-for 嵌套,每个v-for 作用域都可以访问到父级作用域

* 写法上 of  可替代  in 

v-for 与对象

<li v-for="(value, key, index) in myObject">
  {{ index }}. {{ key }}: {{ value }}
</li>

v-for  数字

<span v-for="n in 10">{{n}}</span>
// 此处 n 的值从  1  开始

不推荐v-if 和v-for 一起使用,v-if 优先级更高,这意味着 v-if 的添加将无法访问到v-for 作用域定义的变量别名,解决方法,在最外层包一个 <template> 在其上使用v-for

<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

通过key管理状态

Vue 默认按照“就地更新”的策略来更新通过v-for渲染的列表。当数据项的顺序改变时,Vue不会随之移动DOM元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

为了给Vue一个提示,以便他可以跟踪每个节点的标识,从而重用和重新排列现有的元素,需要为每一个元素对应的块提供一个唯一的 key

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

事件处理

1.内联事件处理器:事件被触发时执行的内联 JavaScript 语句

const count = ref(0)

<button @click="count++">Add +</button>
<p>Count is : {{count}}</p>

// 传参
function say(message) {
  alert(message)
}
<button @click="say('hello')">Say hello</button>


// 访问原生DOM事件
<button @click="warn('aaa',$event)"></button>
<button @click="(event) => warn('aa',event)"></button>

2.方法事件处理器:一个指向组件上定义的方法的属性名或是路径

const name = ref('Vue.js')

function greet(event) {
  alert(`Hello ${name.value}!`)
  // `event` 是 DOM 原生事件
  if (event) {
    alert(event.target.tagName)
  }
}

<!-- `greet` 是上面定义过的方法名 -->
<button @click="greet">Greet</button>

* 方法与内联事件判断:foofoo.bar 和 foo['bar'] 会被视为方法事件处理器,而 foo() 和 count++ 会被视为内联事件处理器。

事件修饰符

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

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

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

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

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

<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>

<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>

<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>

表单输入绑定

// input 
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="请输入"/>


// checkbox 多个复选框绑定到同一个数组
const checkedNames = ref([])
<div>Checked names: {{ checkedNames }}</div>

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>

<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>

<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>


//radio 单按钮
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>


// select 选择器
<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>

修饰符

// .lazy  在 "change" 事件后同步更新而不是 "input"
<input v-model.lazy="msg" />

// .number  输入数字
<input v-model.number="age" />

// .trim 去除用户输入内容中两端的空格
<input v-model.trim="msg" />

生命周期

onMounted 钩子可以用来在组件完成初始化渲染并创建DOM节点后运行代码:

onUpdated:组件因为响应式状态变更而更新其DOM树之后调用。如果需要在某个特定的状态更改后访问更新后的DOM,请使用nextTick()

onUnmounted:在组件实例被卸载之后调用,可在这个钩子中手动清理一些副作用,例如计时器、DOM事件监听或者与服务器的链接。这个钩子在服务器端渲染期间不会被调用。

<script setup>
import {onMounted,onNumounted} from 'vue'

let intervalId
onMounted(()=>{
    intervalId = setInterval(()=>{

    })
})
onNuMounted(() => clearInterval(intervalId))
</script>

onBeforeMount:在组件被挂载之前调用,组件已经完成了其响应状态的设置,但还没创建DOM节点,这个钩子在服务器端渲染期间不会被调用。

onBeforeUpdate:组件即将因为响应式状态变更而更新其DOM树之前调用,这个钩子在服务器端渲染期间不会被调用。

onBeforeUumount:组件实例被卸载之前调用

侦听器

watch() :第一个参数可以是一个ref(包括计算属性)、一个响应式对象、一个getter函数、或多个数据源组成的数组

const x = ref(0)
const y = ref(0)

// 单个ref
watch(x,(newX) => {
    console.log(`x最新值${newX}`)
})

//getter函数
watch(
    ()=>x.value+y.value,
    (sum) => {
        console.log(`sum of x + y is: ${sum}`)
    }
)
// 监听对象的属性值,不能直接监听要使用getter函数
watch(
    ()=>object.key,
    (newValue) => {

    }
)


//多个来源组成的数组
watch([x,() => y.value],([newX,newY]) => {
    console.log(`x is ${newX} and y is ${newY}`)
})

即时回调的侦听器

传入 immediate:true 创建侦听器时,立即执行一遍回调,然后在相关状态更改时重新请求数据

watch(
    source,
    (newValue,oldValue) => {
        // 立即执行,且当 `source`改变时再次执行
    },
    {immediate:true}
)

一次性侦听器

once:true,回调只在源变化时触发一次

watch(
  source,
  (newValue, oldValue) => {
    // 当 `source` 变化时,仅触发一次
  },
  { once: true }
)

watchEffect()

// 回调会立即执行,每当 todoId.value 变化时,回调会再次执行
watchEffect( async ()=> {
    const response = await fetch(
        `serverurl${todoId.value}`
    )
    data.value = await response.json()
})

模板引用

<script setup>
import {ref,onMounted} from 'vue';

// 声明一个ref 来存放该元素的引用
// 必须和模板里的ref 同名
const input = ref(null)
onMounted(()=>{
    input.value.focus()
})
</script>

<template>
    <input ref="input" />
</template>

传递props 、组件之间事件传递

父组件:
<template>
    <p>组件之间参数及事件传递</p>
    <Child @enlarge-text="function" :title="title"/>
</template>


子组件:Child
<script setup>
const props = defineProps(['title'])
const emit = defineEmits(['enlarge-text'])

console.log(props.title)
emit('enlarge-text')
</script>

<template>
    <h4>{{title}}</h4>
</template>

动态组件

<!-- currentTab 改变时组件也改变 -->
<component :is="tabs[currentTab]"></component>

  • 30
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值