前端vue笔记上传

Ryder 2025-12-15 13 12/15

1.组合式API

标准写法

<script setup>
  import { ref, onMounted } from 'vue'
  // 响应式状态
  // 响应式状态
  const count = ref(0)
  // 用来修改状态、触发更新的函数
  function increment() {
    count.value++
  }
  // 生命周期钩子
  onMounted(() => {
    console.log(`The initial count is ${count.value}.`)
  })
</script>
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

2.响应式变量

2.1 ref函数定义响应式变量

<script setup name="App">
  import { ref } from 'vue'
  let username = ref('张三');
  const onChangeUsername = () => {
    username.value = '李四';
  }
</script>
<template>
  <div>用户名:{{ username }}</div>
  <button @click="onChangeUsername">修改用户名</button>
</template>

2.2 reactive函数定义响应式变量

<script setup name="App">
  import { reactive } from 'vue'
  let author = reactive({username: "张三", age: 18})
  let books = reactive([
    {name: '水浒传',author: '施耐庵'},
    {name: '三国演义',author: '罗贯中'}
  ])
  const onModifyBookName = () => {
    books[0].name = '红楼梦'
  }
  const onUpdateUsername = () => {
    author.username = "李四"
  }
</script>
<template>
  <h1>用户名为:{{author.username}}</h1>
  <button @click="onUpdateUsername">修改用户名</button>
  <table>
    <thead>
      <tr>
        <th>书名</th>
        <th>作者</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="book in books" :key="book.name">
        <td>{{ book.name }}</td>
        <td>{{ book.author }}</td>
      </tr>
    </tbody>
  </table>
  <button @click="onModifyBookName">修改书名</button>
</template>

重新给reactive函数定义的响应式变量赋值,需要通过Object.assign来实现:

Object.assign(books, [{name: '红楼梦',author: '曹雪芹'}])

3.事件绑定

v-on

<script setup name="App">
import { reactive, ref } from "vue"

let count = ref(0);

const subtract = function (value) {
  count.value -= value;
}

</script>

<template>
  <p>{{ count }}</p>
  <button v-on:click="count += 1">加</button>
  <button v-on:click="subtract(10)">减10</button>
</template>

4. 双向绑定 v-model

<script setup>
import {ref} from "vue";
let username = ref("");

let category = ref(0);
</script>

<template>
<div>
<input v-model="username" />
<p>用户名为:{{username}}</p>
</div>

<div>
	<select v-model="category">
		<option value="1">Python</option>
		<option value="2">前端</option>
	</select>
	<p>分类为:{{category}}</p>
</div>
</template>

5.计算属性

computed

<script setup>
import {ref, computed} from "vue";

let width = ref(0);
let height = ref(0);

let area = computed(() => {
    return width.value*height.value;
})
</script>

<template>
    <label for="length">长:</label>
    <input type="number" name="height" v-model="height">
    <label for="width">宽:</label>
    <input type="number" name="width" v-model="width">
    <label for="area">面积:</label>
    <input type="number" name="area" :value="area" readonly>
</template>

6.监听属性

watch

6.1 ref函数

<script setup>
import {ref, watch} from "vue";

let person = ref({
    username: '张三',
    age: 18
})

const onUpdatePerson = () => {
    person.value = {'username': '李四', "age": 20};
}

watch(person, (newValue, oldValue) => {
    console.log(newValue);
})
</script>

<template>
<div>
    <p>用户名:{{ person.username }},年龄:{{ person.age }}</p>
    <button @click="onUpdatePerson">修改person</button>
</div>
</template>

6.2 reactive函数

<script setup>
import {ref, reactive, watch} from "vue";
let university = reactive({
    name: '清华大学', 
    year: 1911
})

const updateUniversityName = () => {
    university.name = '北京大学'
}

// 1. 监听一个子属性的变化
watch(() => univertisy.name, (newValue, oldValue) => {
	console.log('new name: ', newValue);
})

// 2. 监听所有子属性的变化
watch(university, (newValue, oldValue) => {
    console.log(newValue);
})
</script>

<template>
<div>
    <div>大学名称:{{ university.name }}</div>
    <button @click="updateUniversityName">更换大学名称</button>
</div>
</template>

7.生命周期

生命周期函数代表的是Vue实例,或者是Vue组件,在网页中各个生命阶段所执行的函数。生命周期函数可以分为创建阶段、挂载阶段、更新阶段以及卸载阶段。

  • 创建阶段:setup
  • 挂载阶段:onBeforeMountonMounted
  • 更新阶段:onBeforeUpdateonUpdated
  • 卸载阶段:onBeforeUnmountonUnmounted
<template>
    <h2>count为:{{ count }}</h2>
    <button @click="onUpdateCount">更新count</button>
</template>

<script setup>
import {
    ref,
    onBeforeMount,
    onMounted,
    onBeforeUpdate,
    onUpdated,
    onBeforeUnmount,
    onUnmounted
} from 'vue'

// 数据
let count = ref(0)
// 方法
function onUpdateCount() {
    count.value += 1
}
console.log('setup')
// 生命周期钩子
onBeforeMount(() => {
    console.log('挂载之前')
})
onMounted(() => {
    console.log('挂载完毕')
})
onBeforeUpdate(() => {
    console.log('更新之前')
})
onUpdated(() => {
    console.log('更新完毕')
})
onBeforeUnmount(() => {
    console.log('卸载之前')
})
onUnmounted(() => {
    console.log('卸载完毕')
})
</script>

8.自定义组件

8.1 自定义属性

<script setup name="Person">
// Person组件
import {defineProps} from "vue";

// 1. 使用数组的形式
//const props = defineProps(['username'])
// 2. 使用对象的形式
const props = defineProps({
    gender: {
        type: String,
        default: '男'
    },
    username: String,
    age: Number,
    body: {
        height: Number,
        weight: Number
    }
})

</script>

<template>
<p>
    用户名:{{ props.username }},
    年龄:{{ props.age }},
    身高:{{ props.body.height }},
    体重:{{ props.body.weight }}
</p>
</template>
<script setup>
import Person from "./components/Person.vue"
</script>

<template>
<Person :age="18" username="张三" :body="{height: 180, weight: 140}"></Person>
</template>

8.2 自定义事件

<script setup name="Person">
import {defineEmits, ref} from "vue";

let steps = ref(0);

const emit = defineEmits(['change']);

const onUpdate = () => {
    steps.value += 10
    emit('change', steps.value);
}

</script>

<template>
<button @click="onUpdate">行走10步</button>
</template>
<script setup>
import Person from "./components/Person.vue"

const onPersonChange = (steps) => {
    console.log("步行了:", steps);
}
</script>

<template>
<Person @change="onPersonChange"></Person>
</template>

8.3 定义v-model

<script setup name="Person">
import {defineModel, watch} from "vue";

let steps = defineModel();
const onUpdate = () => {
    steps.value += 10;
}
watch(steps, (newValue, oldValue) => {
    console.log("Person中监听到steps:", newValue);
})

</script>

<template>
<button @click="onUpdate">行走10步</button>
</template>
<script setup>
import {ref, watch} from "vue";
import Person from "./components/Person.vue"

let steps = ref(0);
watch(steps, (newValue, oldValue) => {
    console.log("App中监听到的:", newValue);
})
</script>

<template>
<Person v-model="steps"></Person>
</template>

9.插槽

<template>
<button type="submit">
    <slot></slot>
</button>
</template>
<template>
<SubmitButton>登录</SubmitButton>
</template>

10.路由VueRouter

10.1 基本使用

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',
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(router)

app.mount('#app')
<script setup>
import { RouterLink, RouterView } from 'vue-router'
</script>

<template>
  <header>
    <div class="wrapper">
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>

10.2 嵌套路由

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },{
      path: '/news',
      component: () => import('../views/news/NewsView.vue'),
      name: 'news',
      children: [{
        path: 'detail', 
        name: 'news-detail', 
        component: import('../views/news/NewsDetailView.vue')
      }]
    },
    {
      path: '/about',
      name: 'about',
      component: () => import('../views/AboutView.vue')
    }
  ]
})
<template>
<ul>
    <li><RouterLink :to="{name: 'news-detail'}">新闻1</RouterLink></li>
    <li>新闻2</li>
    <li>新闻3</li>
</ul>
<RouterView></RouterView>
</template>

10.3 路由传参

10.3.1 路由指定参数

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    path: '/news',
    component: () => import('../views/news/NewsView.vue'),
    name: 'news',
    children: [{
      path: 'detail/:pk',
      name: 'news-detail',
      component: import('../views/news/NewsDetailView.vue')
    }]
    }
  ]
})
<RouterLink :to="{name: 'news-detail', params: {pk: 1}}">新闻1</RouterLink>
<script setup name="NewsDetailView">
  import { onMounted } from 'vue';
  import { useRoute } from 'vue-router';

  const route = useRoute();

  onMounted(() => {
    const pk = route.params.pk;
    console.log(pk);
  })
</script>

10.3.2 查询字符串传参

<RouterLink :to="{name: 'news', query: {page: 1}}">News</RouterLink>
<script setup name="NewsView">
  import { onMounted } from 'vue';
  import {useRoute} from "vue-router";

  const route = useRoute();

  onMounted(() => {
    console.log(route.query);
  })
</script>

10.4 编程式导航

router.push跳转
<script setup>
  import {useRouter} from "vue-router";

  const router = useRouter();

  // 字符串路径
  router.push('/users/eduardo')

  // 带有路径的对象
  router.push({ path: '/users/eduardo' })

  // 命名的路由,并加上参数,让路由建立 url
  router.push({ name: 'user', params: { username: 'eduardo' } })

  // 带查询参数,结果是 /register?plan=private
  router.push({ path: '/register', query: { plan: 'private' } })

  // 带 hash,结果是 /about#team
  router.push({ path: '/about', hash: '#team' })
</script>
const username = 'eduardo'
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user
router.replace替换
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })

10.5 守卫

10.5.1 全局守卫

router.beforeEach((to, from) => {
  if (
    // 检查用户是否已登录
    !isAuthenticated &&
    // ❗️ 避免无限重定向
    to.name !== 'Login'
  ) {
    // 将用户重定向到登录页面
    return { name: 'Login' }
  }
})
router.afterEach(function(to,from){
  console.log('to:',to);
  console.log('from:',from);
})

10.5.2组件内导航守卫

beforeRouteLeave (to, from) {
  const answer = window.confirm('本页面还未保存,您确定要离开吗?')
  if (!answer) return false
}

10.5.3 路由导航守卫

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]

11 Pinia

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }

  return { count, increment }
})

例:

import { defineStore } from 'pinia'

export const useTodos = defineStore('todos', {
  state: () => ({
    /** @type {{ text: string, id: number, isFinished: boolean }[]} */
    todos: [],
    /** @type {'all' | 'finished' | 'unfinished'} */
    filter: 'all',
    // 类型将自动推断为 number
    nextId: 0,
  }),
  getters: {
    finishedTodos(state) {
      return state.todos.filter((todo) => todo.isFinished)
    },
    unfinishedTodos(state) {
      return state.todos.filter((todo) => !todo.isFinished)
    },
    /**
     * @returns {{ text: string, id: number, isFinished: boolean }[]}
     */
    filteredTodos(state) {
      if (this.filter === 'finished') {
        // 调用其他带有自动补全的 getters ✨
        return this.finishedTodos
      } else if (this.filter === 'unfinished') {
        return this.unfinishedTodos
      }
      return this.todos
    },
  },
  actions: {
    // 接受任何数量的参数,返回一个 Promise 或不返回
    addTodo(text) {
      // 你可以直接变更该状态
      this.todos.push({ text, id: this.nextId++, isFinished: false })
    },
  },
})

 

 

- THE END -

Ryder

12月15日15:48

最后修改:2025年12月15日
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论