欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 尚硅谷Vue入门视频 笔记

尚硅谷Vue入门视频 笔记

2024/10/25 8:27:04 来源:https://blog.csdn.net/qq_29922685/article/details/141857537  浏览:    关键词:尚硅谷Vue入门视频 笔记

尚硅谷视频:https://www.bilibili.com/video/BV1Zy4y1K7SH/?spm_id_from=333.999.0.0&vd_source=cec13bbe100bddfff8baf29d18ed8994

文章目录

  • 模板语法
  • data与el的2种写法
  • MVVM模型
  • 事件
    • 事件修饰符
    • 事件的基本使用
  • 计算属性
    • 简写形式
  • 监视属性
  • 绑定样式
  • 条件渲染
  • 列表渲染
  • 收集表单数据
  • 生命周期函数
  • 非单文件组件
  • 单文件组件
  • Vue脚手架
  • main.js
  • App.vue
  • 其他组件
  • ToDoList总结
  • vue组件什么是会被销毁
  • Vuex
    • 创建store
    • 使用

模板语法

  • 插值语法
<h1>{{name}}
</h1>
  • 指令语法
单向数据绑定
<h1 v-bind:href = "js表达式"></h1>
<h1 :href = "js表达式"></h1>
双向数据绑定 一般用在表单类元素上 默认收集value值
<input  type = "text" v-model:value="name"/>
<input  type = "text" v-model="name"/>

data与el的2种写法

  • el有2种写法

    • (1).new Vue时候配置el属性。
    • (2).先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值。
  • data有2种写法

    • (1).对象式

      data: {name: 'shanghai'
      }
      
    • (2).函数式

      data (){console.log('@@@', this); //此时this是Vuereturn {name: 'shanghai'}
      }
      

如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。

  • 一个重要的原则:
    由Vue管理的函数(例如data),一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。

MVVM模型

  • MVVM模型

    • M:模型(Model) :data中的数据
    • V:视图(View) :模板代码
    • VM:视图模型(ViewModel):Vue实例
  • 观察发现:

    • data中所有的属性,最后都出现在了vm身上。
    • vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。

事件

<h1 @click="showInfo" >点我提示信息</h1>

事件修饰符

1.prevent:阻止默认事件(常用);
<a href="https://www.baidu.com" @click.prevent="showInfo" >点我提示信息</a>2.stop:阻止事件冒泡(常用);
修饰符也可以连用,例如下面事例是即阻止冒泡同时也阻止默认行为
<div class="demo1" @click="showMsg(1)">
<button @click.stop="showMsg(2)">点我提示信息</button>
<!--修饰符也可以连用,例如下面事例是即阻止冒泡同时也阻止默认行为-->
<!--<a href="https://www.google.com.tw" @click.prevent.stop="showInfo">谷歌台湾</a>-->
</div>3.once:事件只触发一次(常用);4.capture:使用事件的捕获模式;
<!-- capture事件的捕获模式 让事件以捕获的方式来处理(先捕获再冒泡)-->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">div2</div>
</div>5.self:只有event.target是当前操作的元素时才触发事件;
<!-- self 只有event.target是当前操作的元素时才触发事件(变相阻止冒泡)-->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
<!--passive:事件的默认行为立即执行,无需等待事件回调执行完毕;-->
<!--scroll滚动条一滚动就会触发的事件 wheel鼠标滚轮事件-->
<ul class="list" @scroll.passive="demo"><li>1</li><li>2</li><li>3</li><li>4</li>
</ul>

正常输出2、1,@click.stop输出2, @click.capture输出1,2(先捕获再冒泡

请添加图片描述

事件的基本使用

  1. 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名
  2. 事件的回调需要配置在methods对象中,最终会在vm上
  3. methods中配置的函数,不要用箭头函数!否则this就不是vm了
  4. methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象
  5. @click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参
<button v-on:click="showInfo1">点我提示信息1</button>
<!--简写形式 @click-->
<button @click="showInfo2($event,66)">点我提示信息2</button>showInfo2(e,num){console.log(e.target);//console.log(`接收参数:${num}`);
}

计算属性

  1. 定义:要用的属性不存在,要通过已有属性计算得来。
  2. 原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
  3. get函数什么时候执行?
    • 初次读取时会执行一次。
    • 当依赖的数据发生改变时会被再次调用。
  4. set函数什么时候执行?
    • 修改计算属性所依赖的普通属性(放在data里面的)
  5. 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
  6. 备注:
    1. 计算属性最终会出现在vm上,直接读取使用即可。
    2. 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<div>
姓:<input type="text" v-model="firstName"/><br/><br/>名:<input type="text" v-model="lastName"/><br/><br/>测试:<input type="text" v-model="test"/><br/><br/>全名: <input type="text" v-model="fullName"/><br/><br/>全名: <span>{{ fullName }}</span>
</div>
<script type="text/javascript">const vm = new Vue({el: '#root',data: {//data里的都是属性firstName: '张',lastName: '三',test:'test'},//计算属性--> 旧属性加工computed: {fullName: {//get的作用,当读取fullName时get就会被调用,且返回值就做为fullName的值//defineProperty//注意vm._data是不存在计算属性的//计算属性算完之后直接丢到了viewModel实例对象身上/*** get的调用时机* 1.初次读取计算属性时* 2.所依赖的数据(data中的属性)发生变化时,不改变的话直接读缓存* 3.methods没有缓存,读几次就调用几次无论要用的数据是否发生变化*  @returns {string}*/get(){//此时get函数中的this指向是vmconsole.log('get调用了', this);return this.firstName + '-' + this.lastName},/*** set什么时候调用*   1.当fullName被修改时* @param value*/set(value){console.log('set调用了', value);//修改计算属性所依赖的普通属性(放在data里面的)//this === vmconst [ firstName, lastName ] = value.split('-');console.log('firstName', firstName);console.log('lastName', lastName);this.firstName = firstName;this.lastName = lastName; //依赖属性发生改变之后,计算属性自动改变}}}});</script>

简写形式

computed: {//简写形式//前提:计算属性只考虑读取不考虑修改 set丢了//简写计算书写为一个函数(这个函数当成getter使用), 注意不要写箭头函数//执行完getter之后,vm直接保存返回的数据为fullName属性的属性值,此时vm.fullName不是函数而是一个确切的计算值fullName: function (){return this.firstName + '--' + this.lastName;}
}

监视属性

  1. 当被监视的属性变化时, 回调函数自动调用, 进行相关操作

  2. 监视的属性必须存在,才能进行监视

  3. 监视的两种写法:

    1. new Vue时传入watch配置
    2. 通过vm.$watch监视
  4. handler函数

    1. 当被监视属性发生改变就会调用该函数
    2. 接收两个参数,一个是这个状态参数改变前的值,另一个是改变后的旧值
  5. 深度监视:

    1. Vue中的watch默认不监测对象内部值的改变(一层)
    2. 配置deep:true可以监测对象内部值改变(多层)
  6. 简写形式,不需要immediate、deep属性

    watch:{isHot(newValue, preValue){console.log(newValue,preValue);}
    }
    

案例:

<div id="root"><h1>今天天气很 {{ info }}</h1><button @click="changeWeather">切换</button><h3>b的值是:{{ numbers.b }}</h3><button @click="numbers.b++">点我让b加一</button>
</div>
<script type="text/javascript">Vue.config.productionTip = false;const vm = new Vue({el:'#root',data:{isHot: true,numbers:{a:1,b:1,d:{e:2}}},//计算属性computed: {info(){return this.isHot ? '炎热' : '凉爽';}},//改变模版数据的方法methods:{changeWeather(){this.isHot = !this.isHot;}},// watch:{//     //监视的配置对象//     //watch不仅能监视data的普通属性,也可以检测计算属性//     isHot:{//         immediate: true, //当这个属性为true时,页面刚渲染就运行handler函数//         //handler 什么时候调用呢//         //当isHot发生改变就会调用该函数//         //handler接收两个参数,一个是这个状态参数改变前的值,另一个是改变后的旧值//         handler(newValue, preValue){//             console.log('ishot 被修改了');//             console.log(`newValue: ${newValue}, preValue: ${preValue}`);//         }//     },//深度监视numbers中的所有属性numbers:{deep: true, //监视多级结构的属性handler(){console.log('numbers 发生改变')}}// }});//watch的第二种写法,直接采用vm对象实例vm.$watch('isHot', {immediate: true, //当这个属性为true时,页面刚渲染就运行handler函数//handler 什么时候调用呢//当isHot发生改变就会调用该函数//handler接收两个参数,一个是这个状态参数改变前的值,另一个是改变后的旧值handler(newValue, preValue){console.log('ishot 被修改了');console.log(`newValue: ${newValue}, preValue: ${preValue}`);}});
</script>

绑定样式

  1. class样式
    1. 写法:class=“xxx” xxx可以是字符串、对象、数组
    2. 字符串写法适用于:类名不确定,要动态获取。
    3. 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定
    4. 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用
  2. style样式
    1. :style="{fontSize: xxx}"其中xxx是动态值。
    2. :style="[a,b]"其中a、b是样式对象。

条件渲染

  1. v-if
    1. 写法:
      (1).v-if=“表达式”
      (2).v-else-if=“表达式”
      (3).v-else=“表达式”
    2. 适用于:切换频率较低的场景。
    3. 特点:不展示的DOM元素直接被移除。
    4. 注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。
  2. v-show
    1. 写法:v-show=“表达式”
    2. 适用于:切换频率较高的场景
    3. 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
  3. 备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。

列表渲染

语法:

  • 遍历数组、指定次数

​ v-for=“(item, index) in xxx” :key=“yyy”

  • 遍历对象、字符串

    v-for=“(val, key) of xxx” :key=“yyy”

    v-for=“(c, index) of xxx” :key=“yyy”

  • 在Vue修改数组中的某个元素一定要用如下方法,直接修改的话Vue不监听,模板不改变

    • 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    • Vue.set() 或 vm.$set()
    • 原理:
      Vue会监视data中所有层次的数据
      1. 对象中后追加的属性,Vue默认不做响应式处理
      2. 利用vue.set(或者vm. s e t ( ) ) a p i 能够添加的属性变为响应式属性 V u e . s e t ( t a r g e t , p r o p e r t y N a m e / i n d e x , v a l u e ) 或 v m . set())api能够添加的属性变为响应式属性Vue.set(target,propertyName/index,value) 或 vm. set())api能够添加的属性变为响应式属性Vue.set(targetpropertyName/indexvalue)vm.set(target,propertyName/index,value)
      3. 特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
methods:{updateM(){// this.persons[1].name = '马老师';  //奏效// this.persons[1].age = 50;      //奏效// this.persons[1].sex = '男'; //奏效// this.persons[1] = { id: '002', name: '马老师', age: 50, sex:'男' }; //这样修改vue是无法监测数据的this.persons.splice(1,1,{ id: '002', name: '马老师', age: 50, sex:'男' });},addSex(){//这里this === vm//利用vue.set(或者vm.$set())api能够添加的属性变为响应式属性//注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。Vue.set(this.stu, 'sex', '男')// this.$set(this.stu, 'sex', '男');}
}

“响应式”,是指当数据改变后,Vue 会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新

Vue数据响应式与双向数据绑定原理区分

数据响应式是指通过数据驱动DOM视图的变化,是单向的过程,而双向数据绑定的数据和DOM是一个双向的关系https://blog.csdn.net/forever__fish/article/details/127163227

收集表单数据

  1. 若:,则v-model收集的是value值,用户输入的就是value值。
  2. 若:,则v-model收集的是value值,且要给标签配置value值。
  3. 若:
  4. 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
  5. 配置input的value属性:
    1. v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
    2. v-model的初始值是数组,那么收集的的就是value组成的数组
  6. 备注:v-model的三个修饰符:
    1. lazy:失去焦点再收集数据
    2. number:输入字符串转为有效的数字
    3. trim:输入首尾空格过滤
<div id="root"><form @submit.prevent="demo"><!--写了label则点击它也能使指定的input获取焦点 for属性的值为指定元素的id--><label for="demo">账号:</label><!--v-model主要用来双向绑定输入类表单value值--><input type="text" id="demo" v-model.trim="userInfo.account"/><br/>密码: <input type="password" v-model="userInfo.password"/><br/>性别:<!--一组radio单选框的name值一定要相同 设置value值好让v-model去双向绑定-->男:<input type="radio" v-model="userInfo.sex" name="sex" value="male"/>女:<input type="radio" v-model="userInfo.sex" name="sex" value="female"/><br/>年龄: <input type="number" v-model.number="userInfo.age"/><br/>爱好:<!--如果没有value值则v-model收集checked元素-->学习 <input v-model="userInfo.hobby" type="checkbox" value="study"/>打游戏 <input v-model="userInfo.hobby" type="checkbox" value="game"/>吃饭 <input v-model="userInfo.hobby" type="checkbox" value="eat" /><br/>所属校区<select v-model="userInfo.city"><option value="">请选择校区</option><option value="Beijing">北京</option><option value="Shanghai">上海</option><option value="Shenzhen">深圳</option><option value="Wuhan">武汉</option></select><br/>其他信息<textarea v-model.lazy="userInfo.other"></textarea><br/><input type="checkbox" v-model="userInfo.ifAgree"/>阅读并接受<a href="https://www.google.com.tw">《用户协议》</a><button>提交数据</button></form>
</div>
<script type="text/javascript">Vue.config.productionTip = false;const vm = new Vue({el: '#root',data:{userInfo:{account: '',password: '',sex: 'male',age:'',hobby:[],city:'',other:'',ifAgree:''}},methods:{demo(){//json转换为stringconsole.log(JSON.stringify(this.userInfo));}}})
</script>

生命周期函数

在这里插入图片描述

<script>
export default {name: "demo",data() {return {msg: "Welcome to Your Vue.js App",msg1: "Welcome to Your Vue.js App1",}},methods: {reverseMessage() {this.msg = this.msg.split("").reverse().join("")}},computed: {fullMessage: function() {return this.msg + " " + this.msg},fullMessage2: {get() {console.log("get 调用了")},set(value) {console.log("set 调用了");this.msg = value.split(" ").slice(0, 1).join("");}}},watch: {msg(val, oldVal) {console.log("watch msg 调用了", val, oldVal)},msg1:{immediate:true,deep:true,handler(val,oldVal){console.log("watch 调用了 msg1", val, oldVal)}}}
}
</script>

非单文件组件

  • Vue.extend() 是vc对象

  • new vue()是vm对象

  • const school = Vue.extend(options) 可简写为:const school = options
    
  • 为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。所以vm与vc属性配置并不是一模一样,尽管vc底层复用了很多vm的逻辑

  • 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype

  • 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

<script type="text/javascript">Vue.config.productionTip = false;const school = Vue.extend({template: `<div><h1>学校名称:{{ name }}</h1><h1>学校地址:{{ address }}</h1><button @click="showname">点我提示学校名</button></div>`,data(){return {name: '武汉科技大学',  //vuecomponent的实例对象address:'武汉'}},methods:{showname(){console.log(this);console.log(this.name);}}});// console.log(typeof school, school); //所谓的组件就是构造函数(VueComponent);//测试组件const test = Vue.extend({template:  `<h1>panyue</h1>`});//hello组件const hello = Vue.extend({template:`<div><h1>{{ msg }}</h1><test></test></div>`,data(){return {msg: '你好'}},components: {test}})const vm = new Vue({el:"#root",components:{school,hello}});//验证school与hello并不是同一个VueComponent构造函数// school.a = 99;// console.log('@', school);// console.log('#', hello);// console.log(school === hello);// console.log(school.a, hello.a);
</script>

单文件组件

  • 普通组件School.veu

    • template 写HTML
    • script 创建vc 暴露vc export default {}
    • style 写css
  • App组件 汇总其他组件 components:{School, Student}

  • main.js 创建vm

    //创建vm
    import App from './App';
    //如果文件
    new Vue({el: '#root',template:`<App></App>`,components:{App}
    });
    
  • index.html 准备root容器

mixin

在这里插入图片描述

Vue脚手架

  • npm install -g @vue/cli
  • vue create xxx
  • 启动项目 npm run serve
  • 打包项目 npm run build

在这里插入图片描述

main.js

入口文件

import {createApp} from 'vue'
import App from './App.vue'
import * as VueRouter from 'vue-router';
import routes from "./config/route";
import Vant from 'vant';
import 'vant/lib/index.css';
import '../global.css'const app = createApp(App);const router = VueRouter.createRouter({// 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。history: VueRouter.createWebHistory(),routes, // `routes: routes` 的缩写
})app.use(Vant);
app.use(router);
app.mount('#app')

App.vue

//vue2
<template><img alt="Vue logo" src="./assets/logo.png"><HelloWorld msg="Welcome to Your Vue.js App"/>
</template><script>
import HelloWorld from './components/HelloWorld.vue'export default {name: 'App',components: {HelloWorld}
}
</script>//vue3
<template><BasicLayout />
</template><script setup lang="ts">
import BasicLayout from "./layouts/BasicLayout.vue";
</script><template><BasicLayout />
</template><style></style>

其他组件

<template><van-nav-bar:title="title"left-arrow@click-left="onClickLeft"@click-right="onClickRight"><template #right><van-icon name="search" size="18"/></template></van-nav-bar><div id="content"><router-view/></div><van-tabbar route><van-tabbar-item to="/" icon="home-o" name="index">主页</van-tabbar-item><van-tabbar-item to="/team" icon="search" name="team">队伍</van-tabbar-item><van-tabbar-item to="/user" icon="friends-o" name="user">个人</van-tabbar-item></van-tabbar>
</template><script setup lang="ts">
import { useRouter } from "vue-router";
import {ref} from "vue";
import routes from "../config/route";const router = useRouter();
const DEFAULT_TITLE = '伙伴匹配';
const title = ref(DEFAULT_TITLE);/*** 根据路由切换标题*/
router.beforeEach((to, from) => {const toPath = to.path;const route = routes.find((route) => {return toPath == route.path;})title.value = route?.title ?? DEFAULT_TITLE;
})const onClickLeft = () => {router.back();
};const onClickRight = () => {router.push('/search')
};</script><style scoped>
#content {padding-bottom: 50px;
}
</style>

ToDoList总结

在这里插入图片描述

vue组件什么是会被销毁

页面关闭、路由跳转、v-if和改变key值

Vuex

在这里插入图片描述

创建store

./src/store/index.js

import {createStore} from "vuex";
import {nanoid} from "nanoid";const state = {todos: JSON.parse(localStorage.getItem('todos')) || []
};const mutations = {saveTodos(state, value) {localStorage.setItem('todos', JSON.stringify(value))},addTodo(state, input) {state.todos.unshift({id: nanoid(),label: input,done: false})},allChecked(state, checked){for(let i=0;i<state.todos.length;i++){state.todos.splice(i,1,{...state.todos[i], done: checked})}},delDone(state){console.log("delDone:", state.todos)const todoss = state.todos.filter(item => !item.done);// 有两个值时,第一个值为删除的位置,第二个值为删除的个数;state.todos.splice(0,state.todos.length)// 有三个或者多个值时,第一个值为插入元素的位置,第二个值为替换的个数,后面的值都为插入的新元素;state.todos.splice(0,todoss.length,...todoss)},editTodo(state, [id, label]){const index = state.todos.findIndex(item => item.id === id);state.todos[index].label = label;}};const getters = {done(state) {return state.todos.filter(item => item.done).length;},total(state) {return state.todos.length;}
};
// 创建一个新的 store 实例
const store = createStore({state,mutations,getters
});export default store;

使用

main.js

app.use(store);

./src/App.vue

<template><Layout/>
</template><script setup>
import { reactive, provide ,watch, getCurrentInstance} from 'vue'
import Layout from "@/components/Layout.vue";
import {nanoid} from 'nanoid';
import { useStore } from 'vuex'const proxy = getCurrentInstance();
console.log(proxy);// const readStore = proxy.$store.state.todos;
const store = useStore()
const readStore = store.state.todos;const todos = reactive(readStore)watch(todos, (todos, prevTodos) => {store.commit('saveTodos', todos)
},{ deep: true })</script><style></style>

./src/components/MyFooter.vue

<script setup>
import {ref, inject, getCurrentInstance, watch, computed} from 'vue'
import {useStore, mapGetters} from "vuex";const store = useStore();
const todos = store.state.todos// 使用computed保留响应式
const done = computed(()=>{return store.getters.done
});
const total = computed(()=>{return store.getters.total
})// const delDone = inject('delDone');const checked = ref(false)// const done = ref(todos.filter(item => item.done).length)
// const total = ref(todos.length)
//
// watch(todos,(todos, prevTodos) => {
//     console.log("todos Change", todos);
//     console.log("done", done);
//     console.log("total", total);
//
//     done.value = todos.filter(item => item.done).length;
//     total.value = todos.length;
//
//     },
//     { deep: true }
// )function allChecked() {store.commit("allChecked",checked.value);// checked.value =!checked.value;}
function delDone(){store.commit("delDone");checked.value = false;
}</script><template><el-row :gutter="5"><el-col :span="10" ><el-checkbox label="全部完成" @change="allChecked()" v-model="checked"/></el-col><el-col class="mx-0" :span="10" ><el-text class="mx-1" size="default">完成情况:{{done}}/{{total}}</el-text></el-col><el-col :span="4"><el-button type="danger" size="small" @click="delDone">Del Done</el-button></el-col></el-row>
</template><style scoped>.el-row {height: 100%;padding: 2px 2px;}
.el-button{font-weight: normal;margin: 0 auto;width: 100%;height: 100%;text-align: center;}
.mx-0 {text-align: center;}.mx-1 {height: 100%;width: 100%;margin: 0 auto;
}</style>

使用computed保留getters响应式

// 使用computed保留响应式
const done = computed(()=>{return store.getters.done
});
const total = computed(()=>{return store.getters.total
})

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com