尚硅谷Vue入门视频 笔记

news2024/9/21 2:40:56

尚硅谷视频: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是Vue
          return {
          	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指向是vm
                    console.log('get调用了', this);
                    return this.firstName + '-' + this.lastName
                },
                /**
                 * set什么时候调用
                 *   1.当fullName被修改时
                 * @param value
                 */
                set(value){
                    console.log('set调用了', value);
                    //修改计算属性所依赖的普通属性(放在data里面的)
                    //this === vm
                    const [ 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转换为string
                console.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
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2100699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多线程篇(可见性 原子性 有序性(可见性))(持续更新迭代)

目录 一、volatile&#xff08;关键字&#xff09;&#xff08;并发编程之美&#xff09; 1. 前言 2. synchronized与volatile关键字对比 3. 什么时候使用volatile关键字 二、volatile&#xff08;关键字&#xff09;&#xff08;深入理解JVM第三版&#xff09; 1. 前言 …

儿童护眼灯哪个牌子好?家长必看这些眼科医生推荐的台灯

如今&#xff0c;学生们经常长时间使用平板电脑、手机和电脑等电子设备&#xff0c;这些设备的屏幕会产生频闪和蓝光辐射&#xff0c;进而影响视力健康。因此&#xff0c;护眼成为了家长们普遍关心的问题。视力疲劳和眼部疾病不仅会影响个人的生活质量&#xff0c;还可能引发长…

申请超长期IP地址SSL证书

随着互联网技术的不断发展&#xff0c;信息安全成为了企业和个人关注的核心议题之一。SSL证书不仅能够加密网站的通信数据&#xff0c;保护用户隐私&#xff0c;还能增强网站的可信度&#xff0c;提升搜索引擎排名等。通常情况下&#xff0c;SSL证书是绑定到域名上的&#xff0…

09--kubernetes持久化存储和StatefulSet控制器

前言&#xff1a;本章是k8s持久化存储的详细笔记&#xff0c;由持久化引申出来的statefulset控制器和无头svc都会在本章有详细记录。 1、K8s持久化存储PV和PVC 在前面文章已经使用卷挂载的方式将pod文件持久化保存在宿主机中&#xff0c;但实际工作中pod往往会以多副本形式存…

骨传导耳机哪个牌子最好?今天安利五款好口碑骨传导耳机!

基于对运动耳机多年的使用和深入研究&#xff0c;我想传达几个朴素却重要的观点&#xff1a;购买前请三思&#xff0c;避免盲目追求潮流。虽然网络上的热门款式引人瞩目&#xff0c;但它们的热度可能转瞬即逝&#xff1b;而高价位的知名品牌耳机&#xff0c;虽然品质有保证&…

SpringBoot整合Thymleaf实现页面静态化

1. 问题需求分析 在做乐优商城时&#xff0c;页面是通过Thymeleaf模板引擎渲染后返回到客户端。当商品详情页数据渲染时&#xff0c;在后台需要大量的数据查询&#xff0c;而后渲染得到HTML页面。在用户访问量大的情况下会对数据库造成压力&#xff0c;并且请求的响应时间过长…

开放式耳机与入耳式耳机相比,有哪些优劣势?权威推荐5个实用好用品牌

​开放式耳机其实相对于入耳式耳机来说区别还是比较大的。开放式耳机现在超火&#xff0c;它们不塞进耳朵&#xff0c;这样长时间戴着耳朵也不会难受&#xff0c;还能保护耳朵卫生&#xff0c;特别受爱运动和喜欢研究耳机的朋友们欢迎。不过市面上的开放式耳机太多了&#xff0…

glsl着色器学习(三)

前面两篇文章已经创建好了顶点着色器和片段着色器并编译成功&#xff0c;下面将创建program(程序)&#xff0c;将着色器链接起来 创建Program const prg gl.createProgram(); gl.attachShader(prg, vertexShader); gl.attachShader(prg, fragmentShader); gl.linkProgram(pr…

【无标题】docker-compose一键部署项目,haproxy容器代理多个web或java容器

# 创建脚本&#xff0c;可以在java环境中运行任何的jar包或者war包#!/bin/bash/usr/local/jdk/bin/java -jar /java/src/*.?ar 一、思路分析&#xff1a; &#xff08;1&#xff09;nginx 1、下载镜像&#xff0c;将本地的dist项目的目录挂载在容器的/usr/share/nginx/html/ …

LLM大模型教程:大模型技术名词和概念太多了,一手学习笔记

、、 构建AI化需要的知识体系 Semantic Kernel Semantic Kernel是Microsoft推出的一个开源框架&#xff0c;旨在帮助开发者构建和部署AI应用&#xff0c;特别是那些需要理解和生成自然语言的应用。它提供了一种结构化的方式来定义和管理技能&#xff08;Skills&#xff09;&…

【Canvas技法】五种函数化回文边纹纹饰荟萃

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>五种函数化回文边纹纹饰荟萃</title><style type"text…

一文速学ChatBi“与数据库对话“大模型技术原理及框架一览

前言 上期写了NL2SQL&#xff0c;相信看过的朋友应该都对现在大模型在数据交互办公层面的探索和发展都十分感兴趣&#xff0c;在此商业化的产品市场上也有很多&#xff0c;比如阿里云的析言GBI&#xff1a; 腾讯云的ChatBI&#xff1a; 像此类的产品可以说是最贴切业务的。 在…

C++笔记16•数据结构:关联式容器map和set•

map和set 1.关联式容器 前面介绍的的是序列式容器&#xff1a;vector、list、deque等容器。这次博客介绍STL新的容器成员&#xff0c;那就是关联式容器&#xff1b;顾名思义关联式容器就是容器存在中的数据之间存在联系&#xff08;关联&#xff09;。与序列式容器不同的是&am…

linux入门系列【1】常用命令

一、简介 linux 基本操作命令,便于我们去使用命令帮助我们去检索和排查问题 二、常用命令 1.磁盘空间排查 1.1 查看磁盘空间分布情况 du -ah .|sort -hr 在对应目录下执行则是查看对应目录的文件分布以及大小情况,一般用于查看某个文件夹目录数据情况 1.2 查看深度层级为…

Java中的Set(如果想知道Java中有关Set的知识点,那么只看这一篇就足够了!)

前言&#xff1a;在Java编程中&#xff0c;集合框架&#xff08;Collections Framework&#xff09;是处理数据结构和算法的基础工具之一。它提供了一套强大且灵活的接口和类&#xff0c;用于存储和操作不同类型的数据集合。在这其中&#xff0c;Set接口扮演着一个重要角色。与…

vue-router基本流程及其案例分析

web发展历程 1.后端实现路由 在这个阶段&#xff0c;前端基本上只写界面&#xff0c;也就是html,css,js那些东西&#xff0c;然后在界面中挖槽用来接后端数据&#xff0c;包括路由也由后端负责&#xff0c;在这个阶段中&#xff0c;web开发非常依赖后端&#xff0c;常见的后端…

系列精选 |【梧桐数据库】产品架构层次解析-总述

梧桐数据库中秋特别活动免费领取大闸蟹 抽奖免费领取大闸蟹 以下是正文 在浩瀚的数据世界里&#xff0c;梧桐数据库犹如一颗璀璨的星辰&#xff0c;它的设计如同一首细腻的诗歌&#xff0c;每一个层次都是优美的韵律&#xff0c;为我们构建了一个强大而灵动的数据天地。 梧桐数…

西中区2024年度安全知识竞赛活动方案

为有效预防安全生产事故的发生&#xff0c;深化西中区全体员工对安全生产的认识&#xff0c;切实提升全体人员的安全意识和自我保护能力&#xff0c;夯实安全知识基础&#xff0c;丰富安全文化内涵&#xff0c;推动安全生产工作更加规范化、系统化&#xff0c;根据西中区安全生…

<数据集>遥感航拍飞机和船舶和识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;19973张 标注数量(xml文件个数)&#xff1a;19973 标注数量(txt文件个数)&#xff1a;19973 标注类别数&#xff1a;2 标注类别名称&#xff1a;[ship,plane] 序号类别名称图片数框数1ship17575416292plane239815…

简单好用的SD卡克隆软件:轻松克隆SD卡

想更换SD卡以提升性能&#xff0c;但不知道如何进行SD卡克隆&#xff1f;不用担心&#xff0c;本文推荐了一款好用SD卡克隆软件&#xff0c;轻松帮你解决问题&#xff01; 为什么要克隆SD卡&#xff1f; SD卡广泛应用于游戏机、手机及其他便携设备。用户常用SD卡存储个人数据…