首页 > 其他分享 >vu3入门

vu3入门

时间:2024-09-08 16:06:20浏览次数:14  
标签:const 入门 value state vu3 console ref log

vue3

注意:从P41开始记笔记

卖座电影 (maizuo.com)

1.p41 父传子prop沟通的重要性

image-20230816073915768

三种传递方式:

<!-- 1.写法1 -->
<Navbar :title="title" left="返回" right="首页"></Navbar>
<button @:click="handleClick()">改变标题的名称</button>

<!-- 2.写法2 -->
<!-- <Navbar v-bind="{
'my-title':'电影',
left: '返回',
right: '首页'
}"></Navbar> -->

<!-- 3.写法3:将写法2抽象为对象进行绑定 -->
<!-- <Navbar v-bind="propObj"></Navbar>
<button @:click="handleClick()">改变标题的名称</button> -->

<!-- <Navbar title="影院"></Navbar>
<Navbar title="我的"></Navbar> -->

2.p42属性验证与默认属性

image-20230816085517765

在Vue中,当组件的prop验证失败时,Vue不会自动阻止这个prop的绑定,而是会在控制台输出一条警告信息。这意味着即使leftshow的验证失败,Vue仍然会使用这个prop的值,并且这个值将会影响模板中的v-show指令。

在你的代码中,leftshow是一个布尔类型的prop,它有一个验证器,这个验证器检查传入的值是否是'true'或'false'。但是,当你传递给leftshow的值不是'true'或'false'时,验证器会返回false,Vue会在控制台输出一条警告,说明leftshow的值无效。

然而,由于v-show指令是基于JavaScript的布尔值来工作的,它期望的是一个布尔值(true或false),如果传入的值不是有效的布尔值,Vue会尝试将其转换为布尔值。例如,如果leftshow的值是空字符串、null、undefined、0、NaN或'',Vue会将其转换为false;如果值是非空字符串、非0的数字、对象、数组等,Vue会将其转换为true

3.P43属性的透传

单向数据绑定:

image-20230816091840287

image-20230816092719159

4.P44 子传父:自定义事件

image-20230816110245640

image-20230816110730466

once:

image-20230816110918552

5.P45-$refs_父组件的强权

image-20230816115628116

6.p46 $parent和$root

image-20230816192949263

7.p47跨级通信_provide和inject

image-20230817083940364

8.P48发布订阅模式

image-20230817092357539

9.p49组件的动态生成

image-20230817114417645

image-20230817114623914

10.p50异步组件加载

使用好处:懒加载,页面需要用到那个组件时才进行加载

image-20230817165021319

image-20230817165200944

11.插槽

11-1.p53

image-20230817181536356

11-2 具名插槽p54

image-20230818113423477

11-3 作用域插槽

说明:可以通过子组件暴露数据给父组件,父组件操作数据,然后再插槽到子组件中

下载axios:

npm install axios --save

image-20230818125040196

12 生命周期

12-1 生命周期创建

lifecycle.16e4c08e

12-2生命周期更新

补充:调用方法执行点击事件,然后需要更新DOM树,但是更新DOM树是一个异步过程

image-20230818155536255

代码参考:

<template>
    <div >
        <button @click="handleClick()">改变echarts宽度</button>
        <div id="main" :style="{width: mywith, height: '400px'}"></div>
    </div>
</template>
<script>


    import * as echarts from 'echarts';
    export default{
        data() {
            return{
                title:"标题",
                mywith: '600px',
                optinon:{}
            }
        },
        
        // 1.没啥用,也无法获取组件的属性
        beforeCreate() {
            console.log(this.title)
        },
        // 2.可以用于对组件属性的初始化
        created() {
            this.title="22222",
            this.optinon = {
                title: {
                    text: 'ECharts 入门示例'
                },
                tooltip: {},
                xAxis: {
                    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
                },
                yAxis: {},
                series: [
                    {
                        name: '销量',
                        type: 'bar',
                        data: [5, 20, 36, 10, 10, 20]
                    }
                ]
            }
        },
        // 3.使用少,生成Dom节点之前一刻,此时无法得到Dom节点
        beforeMount() {

        },
        // 4.Dom节点挂载完成,可以访问Dom节点
        mounted() {
            // 订阅发布
            // ajax
            // setInterval
            // 访问dom

            // 获取节点,送入echarts初始化,生成图表
            // 基于准备好的dom,初始化echarts实例
            // 将myChart挂载到当前对象中,提供method使用
            this.myCharts = echarts.init(document.getElementById('main'));
            // 绘制图表
            this.myCharts.setOption(this.optinon);
        },
        methods: {
            handleClick() {
                this.mywith = '800px'
                // with还是600px
                console.log(document.getElementById('main').style.width)

                // 生命周期update()更新完成之后,执行一个回调函数,可以只更新某一个节点,
                //不像update对所以属性都进行更新
                this.$nextTick(()=>{
                    console.log("nextTick")
                    this.myCharts.resize()
                })
            }
            
        },
        beforeUpdate() {
            console.log("beforeUpdate()方法")
            // with还是600px
            console.log(document.getElementById('main').style.width)
        },
        updated() {
            console.log("updated()方法")
            console.log(document.getElementById('main').style.width)
            // 重新改变echarts大小,我将改变大小放到$nextTick()函数中
            // this.myCharts.resize()
        }
    }
</script>

12-3 生命周期销毁

销毁组件中调用了windows对应的函数不会随着组件销毁而销毁,需要手动在unmounted中销毁

image-20230818163002802

13.swapper

14.自定义组件

15 过度效果(内置组件)

15-1 vue内置组件

image-20230819071858023

15-2 使用css库实现过度效果

官网链接:Animate.css | A cross-browser library of CSS animations.

第一步:下载库

npm install animate.css --save

第二步:引入库

import 'animate.css';

第三步:使用

image-20230819073146955

源码参考:

<template>
    <div>
        
       
        <Transition enter-active-class="animate__animated animate__bounceIn" 
        leave-active-class="animate__animated animate__bounceOut">
            <div v-show="isShow">11111</div>
        </Transition>
        <button @click="handleClick()">显示or隐藏</button>
    </div>
</template>
<script>

    import 'animate.css';
    export default{
        data() {
            return{
                isShow: true
            }
        },
        methods: {
            handleClick() {
                this.isShow = !this.isShow
            }
        }
    }
</script>

<style>

</style>

15-3 列表过度

image-20230819080148062

16 .VCA(Vue Composition API)入门

image-20230819114811487

17.p68ref函数使用

<template>
    app
    <div>
        <!-- 1.如果使用ref封装基本类型值,模板解析时会自动执行myname.value,所以只需要写一个myname就可以了 -->
        {{ myname }}
        <input type="text" ref="myinput">
        <button @click="handleClick()">改变名字</button>
    </div>
    
    
</template>

<script>
    import {ref} from 'vue'
    export default {
        setup() {
            // reactive只能封装对象,ref功能更丰富,可以封装基本类型
            const myname = ref("xurong") // 底层:new Proxy({value: "xurong"})
            const myinput = ref(null)
            const handleClick = () => {
                // 2.使用ref封装基本类型值,事件处理的时候,需要调用value进行处理,使用ref外层都封装了value
                myname.value = "wang"
                
                // 3.可以拿到输入框的值
                // myinput.value拿到代理对象,myinput.value.value:通过代理对象获取输入框中的值
                console.log(myinput.value.value)
            }
            return{
                myname,
                handleClick,
                myinput
            }
        }
        
    }
</script>

18.toRef和toRefs使用

reactive转ref:

image-20230819162201439

ref转reactive:

image-20230819163205858

19.VCL中computed中的计算属性

image-20230819180648186

逻辑复用-函数封装:

第一步:封装

image-20230819190743401

第二步:直接调用即可

image-20230819190847220

19.p72 VAL中的watch和watchEffect

<template>
    <div>
        <input type="text" v-model="mytext">
        <select name="" id="" v-model="opt">
            <option value="aa">aa</option>
            <option value="bb">bb</option>
            <option value="cc">cc</option>
        </select>
        {{reactiveValueTest.testText}}
    </div>
</template>
<script>

    import {ref, watch,reactive} from 'vue'
    export default {
        setup() {
            const mytext = ref("")
            // 1.写法1
            // watch(mytext,(newValue,oldValue)=>{
            //     console.log("同步/异步","ajax",newValue)
            // })

            // 2.写法2
            // watch(()=>mytext.value,(newValue,oldValue)=>{
            //     console.log("同步/异步","ajax",newValue)
            // })

            // 3.写法3:可以监听多组数据源
            // const opt = ref("aa");
            // watch([mytext,opt],(newValue,oldValue)=>{
            //     console.log("同步/异步","ajax",newValue)
            // })   

            // 4.写法4:第一次数据渲染时也打印监听的数据
            const opt = ref("aa");
            watch([mytext,opt],(newValue,oldValue)=>{
                console.log("同步/异步","ajax",newValue)
            },{immediate:true})

            // 5.推荐使用watch使用ref,以下是对reactive实现监听
            const reactiveValueTest = reactive({
                testText: "reactive test111"
            })
            // 对reactive对象中的某个值进行监听
            watch(()=>reactiveValueTest.testText,(newValue,oldValue)=>{
                console.log("同步/异步","ajax",newValue)
            },{immediate:true})

            return {
                mytext,
                opt,
                reactiveValueTest
            }
            
        }
    }
</script>

watchEffect用法:

image-20230820075524362

20.props和emit

父传子:

image-20230820130835454

子传父:

特别要注意父组件监听的参数不要加括号

image-20230820131431939

21.provide和inject

image-20230820161522829

22.生命周期

<template>
    app--{{ v}}
    <button @click="handleClick">更新value</button>
</template>

<script>

    import { onBeforeMount,onMounted,onBeforeUpdate,onUpdated,ref,nextTick} from 'vue';
    export default {
        setup() {
            const v = ref("11111")
            onBeforeMount(()=>{
                console.log("DOM创建之前调用111")
            })
            onMounted(()=>{
                console.log("订阅,ajax,DOM创建后,swiper,echart初始化222")
            }) 
            onBeforeUpdate(()=>{
                console.log("DOM树更新之前调用")
            })
            onUpdated(()=>{
                console.log("DOM树更新之后调用")
            })
            const handleClick = () => {
                v.value = "22222"
                // DOM树更新完成之后调用
                nextTick(()=>{
                    console.log("nextTick")
                })
            }
            return {
                v,
                handleClick
            }
        }
        
    }
</script>

销毁组件时,终止异步函数setInterval

<template>
    <div>
        clear
    </div>
</template>

<script>

    import {onBeforeUnmount,onMounted,onUnmounted} from 'vue'
    export default{
        setup() {
            let clearId
            onMounted(()=>{
                clearId = setInterval(()=>{
                    console.log(11111)
                },1000)
            })
            onBeforeUnmount(()=>{

            })
            onUnmounted(()=>{
                clearInterval(clearId)
            })
        }
    }
</script>

23.setup语法糖,见代码

<template>
    app 
    <div>
        {{ msg }}
        <button @click="handleClick">button</button>
        <div>
            {{ myname }}--{{age }}
        </div>
        <div>
            {{computedName}}
        </div>
        <Child title="电影" @right="handleRightClick"></Child>
    </div>
</template>
<!-- 省略了setup,return -->
<script setup>
    import {ref,reactive,toRefs,computed} from 'vue'
    import Child from './Child.vue'

    const msg = ref("hello,world")
    const obj = reactive({
        myname: "xu",
        age:23
    })
    // 将obj属性值解构出去
    const {myname,age} = {...toRefs(obj)}
    const computedName = computed(()=>myname.value.substring(0,1).toUpperCase()+myname.value.substring(1))
    const handleClick= () => {
        msg.value = "xurong"
    }

    const handleRightClick = (value) => {
        console.log("接收到的子组件值为:",value)
    }
</script>
<template>
    <div>
        <button>返回</button>
        {{ title }}
        <button @click="handHome">首页</button>
    </div>
</template>
<script setup>
    import {defineProps,defineEmits} from 'vue'
    const props = defineProps({
        title: {
            type: String,
            default: "000000"
        }
    })

    // 向父组件传值
    const emit = defineEmits(["right"])
    const handHome = () => {
        emit("right","来自子组件的值")
    }
</script>

24.Vue Router

作用:一个html单页面开发

介绍 | Vue Router (vuejs.org)

24-1 使用

image-20230826221809363

image-20230826221605228

image-20230826221516676

image-20230826221947753

说明:router-view被全局注册了,无需进行引入注册操作

24-2 重定向

方式1:

image-20230826222402091

方式2:

image-20230826222520462

错误路径处理和给路径起别名:

image-20230915093921627

24-3 css嵌套语法:

scss:

image-20240827173703409

24-4 p80 路由跳转

image-20240827175503894

结果:

默认会生成a链接

image-20240827175715855

自定义为li元素,也可以为div

image-20240827175606546

24-5 嵌套路由

效果:image-20230915161304644

image-20230915161114225

自动加载子组件:

image-20240827182352312

24-6 p82 编程导航

1.声明式导航-跳转路径拼接id

image-20240828155210141

2.编程式导航

image-20240828160329302

24-7 p83 动态路由

1.params传参:方式1:路径拼接参数 方式2:对象传参

image-20240828161733262

注意:对象传参需要给上述路径起一个名字

image-20240828163909888

得到携带的参数:

image-20240828165013113

2.query传参:在路径上拼接上?然后拼接上参数进行传参

image-20240828165520907

image-20240828165828244

得到传递的参数:

image-20240828165906269

效果图:

image-20240828165659008

3.返回上一个页面

image-20240828170903915

4.猜你喜欢电影页面跳转(同级别)

image-20240828172824835

结果:

image-20240828173006825

24-8 p84 路由模式

image-20240829073049507

结果:

image-20240829073120605

24-9 p85全局登录拦截

1.只放行登录页面,对其他页面都需要进行登录拦截

// 全局拦截-后台系统,除了登录页面,其他页面都必须授权才能放行访问
router.beforeEach((to,from,next) => {
    let isAuthenticated = localStorage.getItem("token");
    if(to.name !== 'Login' && !isAuthenticated) next({
        name: 'Login'
    })
    else next()
})

2.对特定页面进行登录拦截

对Centers页面进行拦截:设置标记meta表明访问该路径时需要登录

    {
        path:"/center",
        component:Centers,
        meta: {
            requiredAuth: true
        }
    }

逻辑实现:

// 对center页面进行登录拦截
router.beforeEach((to,from,next) => {
    let isAuthenticated = localStorage.getItem("token");
    console.log(to.fullPath)
    if(to.name !== 'Login' && !isAuthenticated && to.meta.requiredAuth) next({
        name: 'Login'
    })
    else next()
})

3.路径拦截通过之后,可以对点击量进行统计

router.afterEach((to,from) => {
    
    // 统计对该电影喜爱数据(可以在路径中获取对应的电影id,然后可以统计该用户对该id统计的次数)
    let filmId = to.params.myid;
    console.log("提交后端用户行为信息",filmId);
})

24-10 组件内的守卫

1.单个组件的拦截--beforeRouteEnter

image-20240829085628878

2.路由更新之前获取请求参数-- beforeRouteUpdate

image-20240829090315323

4.beforeRouteLeave

image-20240829091153621

24-11 路由懒加载--按需导入对应的组件

image-20240829092600836

image-20240829092803658

结果:

image-20240829093327719

24-12 VCL与路由

1.组件注册

image-20240829110849414

2.路由跳转--引入useRouter

image-20240829111955944

3.改造1

image-20240829113440728

4.onMounted,route,router,onBeforeRouteUpdate--setup模式

image-20240829120013454

5.beforeRouteEnter在组合式模式下没有对应的函数

image-20240829121414178

25 vuex

25- 1 简介

npm install vuex@next --save

1.页面中有多个需要共享的状态,引入vuex,便于维护(非父子通信)

2.缓存部分异步数据,减少后端服务的访问,增加用户体验

使用:

注册:

image-20240829151042690

使用vuex创建属性值:决定是否显示Tabbar组件

image-20240829152319938

实践:

image-20240829155224836

image-20240829155103016

结果:

image-20240829155348211

image-20240829155431719

上述为错误示例:isTabbarShow属性值不可跟踪

25-2 mutations

image-20240829180257362

image-20240829180324587

演示:

image-20240829181724897

改进:

image-20240829182350215

开发中常用写法:

image-20240829184205561

25-3 action--缓存数据

image-20240829195631793

image-20240830070731914

如果你希望在 Vuex 中缓存数据,通常的做法是:

在 action 中进行异步请求(例如,从 API 获取数据)。
在异步操作完成后,将数据提交到 mutation 中,mutation 会更新 store 的状态。
一旦数据被提交到 store,它就会被保存在 Vuex 的状态树中,直到你显式地修改它。
状态树中的数据在默认情况下是响应式的,这意味着当状态发生变化时,任何依赖于该状态的组件都会自动更新。如果你想要缓存数据,你可以选择将数据保存在状态树中,这样它就会在组件之间共享,并且可以在多个组件之间保持同步。

25-4 getter

image-20240830120147896

25-5 辅助函数--mapState,mapAction,mapGetters 鸡肋

image-20240830142954145

25-6 vux--module开发

注意:涉及到辅助函数,命名空间,可以结合上一节重复看,我直接没有使用辅助函数

每一类数据对应一个js模块,然后合并到index.js中

index.js:将下面的切分不同module,然后合并:

/**
 * 1.页面中有多个需要共享的状态,引入vuex,便于维护(非父子通信)
   2.缓存部分异步数据,减少后端服务的访问,增加用户体验
 */
import {createStore} from 'vuex'
import {CHANGE_TABBAR,CHANGE_CINEMALIST} from './type.js'

import axios from 'axios'

const store = createStore({
  state() {
    return {
      isTabbarShow: true,
      cinemaList: []
    }
  },
  // 唯一修改状态的位置--同步
  mutations: {
    // showTabbar(state) {
    //   state.isTabbarShow = true;
    // },
    // hiddenTabbar(state) {
    //   state.isTabbarShow = false;
    // }

    [CHANGE_TABBAR](state,playload) {
      state.isTabbarShow = playload
    },
    [CHANGE_CINEMALIST](state,playload) {
      state.cinemaList = playload
    }
  },
  // 同步+异步
  actions: {
    async getCinemaList(store) {
      const res = await axios({
        url: "https://m.maizuo.com/gateway?cityId=440300&ticketFlag=1&k=1628079",
        headers: {
          'x-client-info':'{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777"}',
          'x-host':'mall.film-ticket.cinema.list'
        }
      });
      console.log(res.data.data.cinemas);
      // 提交mutation
      store.commit(CHANGE_CINEMALIST,res.data.data.cinemas);
    }
  },

  // getter store的计算属性
  getters: {
    filterCinemaList(state) {
      return (playload) => {
        return state.cinemaList.filter(item => 
          item.eTicketFlag === playload)
      }
    }
  }
})
export default store

改造:

/**
 * 1.页面中有多个需要共享的状态,引入vuex,便于维护(非父子通信)
   2.缓存部分异步数据,减少后端服务的访问,增加用户体验
 */
import { CHANGE_CINEMALIST } from '../type.js'

import axios from 'axios'

const CinemaModule = {
    state() {
        return {
            cinemaList: []
        }
    },
    // 唯一修改状态的位置--同步
    mutations: {
        // showTabbar(state) {
        //   state.isTabbarShow = true;
        // },
        // hiddenTabbar(state) {
        //   state.isTabbarShow = false;
        // }
        [CHANGE_CINEMALIST](state, playload) {
            state.cinemaList = playload
        }
    },
    // 同步+异步
    actions: {
        async getCinemaList(store) {
            const res = await axios({
                url: "https://m.maizuo.com/gateway?cityId=440300&ticketFlag=1&k=1628079",
                headers: {
                    'x-client-info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777"}',
                    'x-host': 'mall.film-ticket.cinema.list'
                }
            });
            console.log(res.data.data.cinemas);
            // 提交mutation
            store.commit(CHANGE_CINEMALIST, res.data.data.cinemas);
        }
    },

    // getter store的计算属性
    getters: {
        filterCinemaList(state) {
            return (playload) => {
                return state.cinemaList.filter(item =>
                    item.eTicketFlag === playload)
            }
        }
    }
}
export default CinemaModule
/**
 * 1.页面中有多个需要共享的状态,引入vuex,便于维护(非父子通信)
   2.缓存部分异步数据,减少后端服务的访问,增加用户体验
 */
import { CHANGE_TABBAR } from '../type.js'

const TabbarModule = {
    state() {
        return {
            isTabbarShow: true
        }
    },
    // 唯一修改状态的位置--同步
    mutations: {
        // showTabbar(state) {
        //   state.isTabbarShow = true;
        // },
        // hiddenTabbar(state) {
        //   state.isTabbarShow = false;
        // }

        [CHANGE_TABBAR](state, playload) {
            state.isTabbarShow = playload
        }
    }
}
export default TabbarModule
/**
 * 1.页面中有多个需要共享的状态,引入vuex,便于维护(非父子通信)
   2.缓存部分异步数据,减少后端服务的访问,增加用户体验
 */
import {createStore} from 'vuex'
import CinemaModule from './module/CinemaModule'
import TabbarModule from './module/TabbarModule'

const store = createStore({
  modules: {
    CinemaModule,
    TabbarModule
  }
  
})
export default store

代码变动:

老师使用了辅助函数,命名空间,我是直接调用方法和计算属性,我觉得这和普通的方法和计算属性可以区别开来

image-20240830150249225

image-20240830150405778

25-7 vca与vuex

vca模式下,不支持 (辅助函数--mapState,mapAction,mapGetters,底层基于this)所有改造的项目中没有使用辅助函数

25-7 vuex持久化插件

将保存在内存中的数据保存到localStore中

npm install --save vuex-persistedstate

image-20240830164447216

结果;

image-20240830164524032

26.pinia

定义 Store | Pinia (vuejs.org)

26-1 简介

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态.

由于组合式API中vuex不能够很好使用,所以出现了pinia

npm install pinia

26-2 optionStore

1.aciton

image-20240831125428474

image-20240831125738760

2.getters

image-20240831130843995

26-3 setupStore

tabbarStore.js:

import { defineStore } from 'pinia'
import { ref } from 'vue';

// 第一个参数是唯一的storeId
export const useTabbarStore = defineStore("tabbar", () => {
    // state: () => ({
    //     isTabbarShow: true
    // }),
    const isTabbarShow = ref(true);

    // actions: {
    //     change(value) {
    //         // this可以直接获取state对象
    //         this.isTabbarShow = value;
    //     }
    // },

    const change = (value) => {
        isTabbarShow.value = value;
    }
    return {
        isTabbarShow,
        change
    }
})

cinemaStore.js:

import { defineStore } from "pinia";

import axios from 'axios'
import { computed, ref } from "vue";
export const useCinemaStore = defineStore("cinema",() => {
    // state: () => ({
    //     cinemaList: []
    // }),
    const cinemaList = ref([]);

    // actions: {
    //     // 方法
    //     async getCinemaList() {
    //         const res = await axios({
    //             url: "https://m.maizuo.com/gateway?cityId=440300&ticketFlag=1&k=1628079",
    //             headers: {
    //                 'x-client-info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777"}',
    //                 'x-host': 'mall.film-ticket.cinema.list'
    //             }
    //         });
    //         console.log(res.data.data.cinemas);
    //         this.cinemaList = res.data.data.cinemas;
    //     }
    // },
    const getCinemaList = async() => {
        const res = await axios({
            url: "https://m.maizuo.com/gateway?cityId=440300&ticketFlag=1&k=1628079",
            headers: {
                'x-client-info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777"}',
                'x-host': 'mall.film-ticket.cinema.list'
            }
        });
        console.log(res.data.data.cinemas);
        cinemaList.value = res.data.data.cinemas;
    }
    
    // getters: {
    //     // 根据选择的App订票和前台兑换过滤cinemaList,注意该计算属性返回值是一个参数为value的函数
    //     filterCinema(state) {
    //         return (value) => {
    //             return state.cinemaList.filter(item =>
    //                 item.eTicketFlag === value)
    //         }
    //     }
    // }

    // 老师写法:
    // const filterCinema = computed(() => 
    //         // 一个参数为value的函数
    //         // 注意cinemaList是ref包装的
    //         (value) => {return cinemaList.value.filter(item =>
    //                 item.eTicketFlag === value)
    //         } 
    // )
    
    // gpt写法
    // ue 3 中,computed 函数应该返回一个值或者一个函数,而不是一个函数的声明
    const filterCinema = computed(() => {
        // 注意cinemaList是ref包装的
        return (value) => {
          return cinemaList.value.filter(item => item.eTicketFlag === value);
        }
      });
      
    return {
        cinemaList,
        getCinemaList,
        filterCinema
    }
})

27.vant

快速上手 - Vant 4 (vant-ui.github.io)

移动组件库:

npm i vant

27.1 导入vant中的组件作为全局组件和局部组件

1.全局组件:

image-20240831163058819

2.局部组件:

image-20240831163631738

27-2 axios结合Toast组件使用

image-20240831173104736

实现效果:

image-20240831173339926

27-3 List组件

<template>
    <div>
        <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" 
        @load="onLoad" offset="10" :immediate-check="false">
            <van-cell v-for="item in datalist" :key="item.filmId" @click="handleClick(item.filmId)">
                <img :src="item.poster" alt="电影图片展示" style="width: 100px;float: left;">
                <div>
                    {{ item.name }}
                </div>
            </van-cell>
        </van-list>

        <!-- <ul>
            <li v-for="(item, index) in datalist" :key="item.filmId" @click="handleClick(item.filmId)">
                {{ item.name }}
            </li>
        </ul> -->
    </div>
</template>

<script setup>
import axios from 'axios';
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { List as vanList, Cell as vanCell } from 'vant';

const datalist = ref([]);
const router = useRouter();

const loading = ref(false);
const finished = ref(false);
const pageNumber = ref(1);
const totalSize = ref(0);


const handleClick = (id) => {
    router.push(`/detail/${id}`);
}

onMounted(async () => {
    const res = await axios({
        url: "https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=7994369",
        headers: {
            'x-client-info':
                '{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777","bc":"110100"}',
            'x-host':
                'mall.film-ticket.film.list'
        }
    });
    console.log(res.data)
    datalist.value = res.data.data.films;
    console.log(datalist.value[1]);
    totalSize.value = res.data.data.total;
    console.log(totalSize.value)
})


const onl oad = async () => {
    console.log(datalist.value.length)
    if(totalSize.value === datalist.value.length) {
        finished.value = true;
        return
    }
    console.log("到底了");
    pageNumber.value++;
    const res = await axios({
        url: `https://m.maizuo.com/gateway?cityId=110100&pageNum=${pageNumber.value}&pageSize=10&type=1&k=7994369`,
        headers: {
            'x-client-info':
                '{"a":"3000","ch":"1002","v":"5.2.1","e":"172475767310819585259339777","bc":"110100"}',
            'x-host':
                'mall.film-ticket.film.list'
        }
    });
    console.log(res.data.data.films)
    datalist.value = [...datalist.value,...res.data.data.films];
    loading.value = false;
}
</script>
<style scoped lang="scss">

// 外部组件:van-cell为van-list的子节点,无法直接使用类名进行样式绑定,以下为解决方案
// van-cell__value可以借助浏览器的devtool找到
// 深度选择器:表示只要是父节点下有class名为van-cell__value节点,文本都居中显示
:deep(.van-cell__value) {
    text-align: left;
}
ul {
    li {
        padding: 10px;
    }
}
</style>

注意点1:样式渲染

// 外部组件:van-cell为van-list的子节点,无法直接使用类名进行样式绑定,以下为解决方案
// van-cell__value可以借助浏览器的devtool找到
// 深度选择器:表示只要是父节点下有class名为van-cell__value节点,文本都居中显示
:deep(.van-cell__value) {
    text-align: left;
}

注意点2:

image-20240901101052309

28.element-plus

见代码:

29.TypeScript

29-1:组合式API

1.reactive定义自定义类型的对象

import {reactive,ref} from 'vue'
interface IState {
    name:string,
    age: number
}
const state:IState = reactive({
    name: "xiao3",
    age:23
})

2.ref定义变量

法1:

import {ref} from 'vue'
import type {Ref} from 'vue'
const state:Ref<IState> = ref({
    name: "aa",
    age:23
})

法2:

import {ref} from 'vue'
const state = ref<IState>({
    name:"xiao1",
    age: 22
})

3.计算属性使用

onMounted(()=>{
    console.log(mydiv.value?.textContent+"abc")
})
// 指明该计算属性返回为string类型
const computedName = computed<string>(() => {
    return state.value.name.substring(0,1).toUpperCase()+state.value.name.substring(1)
})

4.父传子,子传父

父传子:

image-20240902222211986

子传父:

image-20240902222729425

29-2:ts与路由

image-20240903063656628

image-20240903063334104

image-20240903063417172

image-20240903063528148

image-20240903063605585

29-3 TypeScript与Pinia

image-20240903070049776

image-20240903070137387

标签:const,入门,value,state,vu3,console,ref,log
From: https://www.cnblogs.com/rong-xu-drum/p/18402972

相关文章

  • MySQL入门到精通
    一、创建数据库CREATEDATABASE数据库名称;如果数据库存在,则会提示报错。二、选择数据库USE数据库名称;三、创建数据表CREATETABLE数据表名称;四、MySQL数据类型MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串类型4.1数值类型数值类型类......
  • Vue.js入门系列(二十三):集成第三方动画库、总结过渡与动画、配置代理
    个人名片......
  • Vue.js入门系列(二十二):Vue的`$nextTick`、动画效果与过渡效果
    个人名片......
  • Python入门教程-Python 中的字符串及常用操作有哪些
    字符串是编程语言中最常见和最基础的数据类型之一。在Python中,字符串(string)是用于表示文本数据的序列。无论是处理用户输入、文件读写,还是处理网络数据,字符串都是编程中的关键工具之一。Python提供了许多方便的操作和方法来处理字符串数据。本文将带你从基础入门,详细介绍......
  • python入门
    引言        Python是一种高级编程语言,以其易读性和简洁性而闻名,非常适合初学者入门。Python广泛应用于各种领域,从网站开发到数据分析,再到人工智能和机器学习。本课时将带你走进Python的世界,了解Python的基本知识,并教你如何安装Python环境,使用IDLE或其他适......
  • 算法入门-深度优先搜索2
    第六部分:深度优先搜索104.二叉树的最大深度(简单)题目:给定一个二叉树root,返回其最大深度。二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。示例1:输入:root=[3,9,20,null,null,15,7]输出:3示例2:输入:root=[1,null,2]输出:2第一种思路:感觉递......
  • PostgreSQL入门介绍
    一、PostgreSQL背景及主要功能介绍1、背景PG数据库,全称为PostgreSQL数据库,是一款开源的关系型数据库管理系统(RDBMS)。其起源可以追溯到20世纪80年代末和90年代初,由加拿大的计算机科学家MichaelStonebraker及其团队在加州大学伯克利分校启动。该项目旨在创建一个强大的、......
  • 第49课 Scratch入门篇:骇客任务背景特效
    骇客任务背景特效故事背景: 骇客帝国特色背景在黑色中慢慢滚动着!程序原理: 1、角色的设计技巧 2、克隆体的应用及特效的使用开始编程 1、使用黑色的背景:![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7d74c872f06b4d9fbc88aecee634b074.png#pi......
  • C语言入门:从函数基础到实践精通
    前言欢迎各位老铁和我一起进入C语言的世界,今天我们要讨论的是一个让你更好地理解程序组织方式的核心概念——函数。无论是简单的任务,还是复杂的计算,函数都是编程中不可或缺的一部分。在本篇文章中,我将从基础讲解函数的构成和用法,再深入探讨常用的函数类型及其实际应用。函数......
  • C语言入门:回调函数与递归函数详解
    对于刚刚接触C语言的同学来说,回调函数和递归函数可能听起来有些复杂,但它们是编程中非常有用的工具。在这篇文章中,我将接着上一篇文章详细介绍这两个概念,并通过简单易懂的例子,让你轻松理解它们的作用和使用场景。废话不多说,我们开始吧~1.什么是回调函数?回调函数的概念回......