美文网首页
vue3基本使用

vue3基本使用

作者: HS_d119 | 来源:发表于2022-05-28 10:18 被阅读0次

    1、vue3.0生命周期钩子函数

    • setup 创建实例前
    • onBeforeMount 挂载DOM前
    • onMounted 挂载DOM后
    • onBeforeUpdate 更新组件前
    • onUpdated 更新组件后
    • onBeforeUnmount 卸载销毁前
    • onUnmounted 卸载销毁后

    2、组合API-setup函数

    使用细节:

    • setup 是一个新的组件选项,作为组件中使用组合API的起点。
    • 从组件生命周期来看,它的执行在组件实例创建之前vue2.x的beforeCreate执行。
    • 这就意味着在setup函数中 this 还不是组件实例,this 此时是 undefined
    • 在模版中需要使用的数据和函数,需要在 setup 返回。
    <template>
        <div class="container">
            {{ msg }}
            <button @click="say">点击</button>
        </div>
    </template>
    
    <script>
    export default {
        name: 'App',
        setup() {
            console.log('setup', this);
            const msg = 'Hello';
            const say = () => {
                console.log(1);
            }
            return {
                msg,
                say,
            }
        },
        beforeCreate() {
            console.log('beforeCreate');
        }
    }
    </script>
    

    3、组合API-生命周期

    <template>
        <div class="container">
            Hello
        </div>
    </template>
    
    <script>
    import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated } from 'vue'
    export default {
        name: 'App',
        setup() {
            // 1.DOM渲染前执行
            onBeforeMount(() => {
                console.log('DOM渲染前执行', document.querySelector('.container'));
            })
            // 2.DOM渲染后钩子
            onMounted(() => {
                console.log('DOM渲染后钩子1', document.querySelector('.container'));
            })
            // 可以定义多个相同的构造函数,实现不同的逻辑
            onMounted(() => {
                console.log('DOM渲染后钩子2', document.querySelector('.container'));
            })
            onBeforeUpdate(() => {
                console.log('更新组件前');
            })
            onUpdated(() => {
                console.log('更新组件后');
            })
            onBeforeUnmount(() => {
                console.log('卸载销毁前');
            })
            onUnmounted(() => {
                console.log('卸载销毁后');
            })
        }
    }
    </script>
    

    4、组合API-reactive函数

    定义响应式数据:

    • reactuve是一个函数,它可以定义一个复杂数据类型,成为响应式数据
    • 通常是用来定义响应式对象数据
    <template>
        <div class="container">
            <div>{{ obj.name }}</div>
            <div>{{ obj.age }}</div>
            <button @click="changeName">修改名字</button>
        </div>
    </template>
    
    <script>
    import { reactive } from 'vue'
    export default {
        name: 'App',
        setup() {
            // 普通数据
            // const obj = {
            //     name: 'HS',
            //     age: 18,
            // }
    
            // 响应式数据
            const obj = reactive({
                name: 'HS',
                age: 18,
            })
    
            // 修改名字
            const changeName = () => {
                obj.name = "ZJP";
            }
            return { obj, changeName }
        }
    }
    </script>
    

    5、组合API-toRef函数

    定义响应式数据:

    • toRef是函数,转换响应式对象某个属性为单独响应式数据,并且值是关联的

    使用场景:有一个响应式对象数据,但是模版中只需要使用其中一项数据。

    <template>
        <div>
            {{ name }}
            <button @click="updateName">修改名字</button>
        </div>
    </template>
    
    <script>
    import { reactive, toRef } from 'vue'
    export default {
        name: 'App',
        setup() {
            // 1.响应式数据对象
            const obj = reactive({
                name: 'HS',
                age: 18,
            })
    
            // 2.模板中只需要使用name数据
            // 注意:从响应式数据对象中结构出来的属性数据,不再是响应式数据
            // const { name } = obj; 不能直接解构,出来的是一个普通数据
            const name = toRef(obj, 'name');
            const updateName = () => {
                // toRef转换响应式数据包装成对象,value是存放值的位置
                name.value = "ZJP";
            }
            return {
                name,
                updateName,
            }
        }
    }
    </script>
    

    toRefs

    定义响应式数据:

    • toRefs是函数,转换响应式对象中所有属性为单独响应式数据,对象成为普通对象,并且值是关联的
    <template>
        <div>
            {{ name }}
            {{ age }}
            <button @click="updateName">修改名字</button>
        </div>
    </template>
    
    <script>
    import { reactive, toRefs } from 'vue'
    export default {
        name: 'App',
        setup() {
            // 1.响应式数据对象
            const obj = reactive({
                name: 'HS',
                age: 18,
            })
            // 2.解构或者展开响应式数据对象
            // const { name, age } = obj;
            // console.log(name, age);
            // const obj2 = { ...obj };
            // console.log(obj2);
            // 以上方式导致数据就不是响应式数据了
            const obj3 = toRefs(obj);
            console.log(obj3);
    
            const updateName = () => {
                obj3.name.value = "ZJP";
            }
            return {
                ...obj3,
                updateName,
            }
        }
    }
    </script>
    

    6、组合API-ref函数

    定义响应式数据:

    • ref函数,常用于简单数据类型定义为响应式数据
      • 再修改值,获取值的时候,需要.value
      • 在模板中使用ref申明的响应式数据,可以省略.value
    <template>
        <div>
            {{ name }}
            <button @click="updateName">修改名字</button>
        </div>
    </template>
    
    <script>
    import { ref } from 'vue';
    export default {
        name: 'App',
        setup() {
            const name = ref("HS");
            const updateName = () => {
                name.value = "ZJP";
            }
    
            return {
                name,
                updateName,
            }
        }
    }
    </script>
    

    7、知识运用案例

    基本步骤:

    • 记录鼠标坐标
      • 定义一个响应式数据对象,包含x和y属性。
      • 在组件渲染完毕后,监听document的鼠标移动事件
      • 指定move函数为事件对应方法,在函数中修改坐标
      • 在setup返回数据,模版中使用
    • 累加1功能
      • 定义一个简单数据类型的响应式数据
      • 定义一个修改数字的方法
      • 在setup返回数据和函数,模板中使用
    <template>
        <div class="container">
            <div>坐标</div>
            <div>x: {{ x }}</div>
            <div>y: {{ y }}</div>
            <hr>
            <div>{{ count }} <button @click="add">累加1</button></div>
        </div>
    </template>
    <script>
    import { onMounted, onUnmounted, reactive, ref, toRefs } from 'vue'
    const useMouse = () => {
        // 1. 记录鼠标坐标
        // 1.1 申明一个响应式数据,他是一个对象,包含x y
        const mouse = reactive({
            x: 0,
            y: 0
        })
        // 1.3 修改响应式数据
        const move = (e) => {
            mouse.x = e.pageX
            mouse.y = e.pageY
        }
        // 1.2 等dom渲染完毕。去监听事件
        onMounted(() => {
            document.addEventListener('mousemove', move)
        })
        // 1.4 组件消耗,删除事件
        onUnmounted(() => {
            document.removeEventListener('mousemove', move)
        })
    
        return mouse
    }
    export default {
        name: 'App',
        setup() {
    
            const mouse = useMouse()
    
            // 2. 数字累加
            const count = ref(0)
            const add = () => {
                count.value++
            }
    
    
    
            return { ...toRefs(mouse), count, add }
        }
    }
    </script>
    <style scoped lang="less">
    </style>
    

    8、组合API-computed函数

    定义计算属性:

    • computed函数,是用来定义计算属性的,计算属性不能修改。
    <template>
      <div class="container">
        <div>今年:{{age}}岁</div>
        <div>后年:{{newAge}}岁</div>
      </div>
    </template>
    <script>
    import { computed, ref } from 'vue'
    export default {
      name: 'App',
      setup () {
        // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
        const age = ref(16)
        // 得到后年的年龄
        const newAge = computed(()=>{
          // 该函数的返回值就是计算属性的值
          return age.value + 2
        })
    
        return {age, newAge}
      }
    }
    </script>
    

    高级写法

    <template>
        <div class="container">
            <div>今年:{{ age }}岁</div>
            <div>后年:{{ newAge }}岁</div>
            <input type="number" v-model="newAge" />
        </div>
    </template>
    <script>
    import { computed, ref } from 'vue'
    export default {
        name: 'App',
        setup() {
            // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
            const age = ref(16)
            // 得到后年的年龄
            const newAge = computed({
                // get函数,获取计算属性的值
                get() {
                    return age.value + 2
                },
                // set函数,当你给计算属性设置值的时候触发
                set(value) {
                    age.value = value - 2;
                }
            })
    
            return { age, newAge }
        }
    }
    </script>
    

    9、组合API-watch函数

    定义计算属性:

    • watch函数,是用来定义侦听器的

    监听ref定义的响应式数据

    监听多个响应式数据数据

    监听reactive定义的响应式数据

    监听reactive定义的响应式数据,某一个属性

    深度监听

    默认执行

    <template>
      <div class="container">
        <div>
          <p>count的值:{{ count }}</p>
          <button @click="add">改数据</button>
        </div>
        <hr />
        <div>
          <p>{{ obj.name }}</p>
          <p>{{ obj.age }}</p>
          <p>{{ obj.brand.name }}</p>
          <button @click="updateName">改名字</button>
          <button @click="updateBrandName">改品牌名字</button>
        </div>
      </div>
    </template>
    <script>
    import { reactive, ref, watch } from "vue";
    export default {
      name: "App",
      setup() {
        const count = ref(0);
        const add = () => {
          count.value++;
        };
        // 当你需要监听数据的变化就可以使用watch
        // 1. 监听一个ref数据
        // 1.1 第一个参数  需要监听的目标
        // 1.2 第二个参数  改变后触发的函数
        // watch(count, (newVal,oldVal)=>{
        //   console.log(newVal,oldVal)
        // })
    
        const obj = reactive({
          name: "ls",
          age: 10,
          brand: {
            id: 1,
            name: "宝马",
          },
        });
        const updateName = () => {
          obj.name = "zs";
        };
        const updateBrandName = () => {
          obj.brand.name = "奔驰";
        };
        // 2. 监听一个reactive数据
        watch(obj, () => {
          console.log("数据改变了");
        });
    
        watch(
          () => obj.brand,
          () => {
            console.log("brand数据改变了");
          },
          {
            // 5. 需要深度监听
            deep: true,
            // 6. 想默认触发
            immediate: true,
          }
        );
    
        // 3. 监听多个数据的变化
        // watch([count, obj], ()=>{
        //   console.log('监听多个数据改变了')
        // })
    
        // 4. 此时监听对象中某一个属性的变化 例如:obj.name
        // 需要写成函数返回该属性的方式才能监听到
        // watch(()=>obj.name,()=>{
        //   console.log('监听obj.name改变了')
        // })
    
        return { count, add, obj, updateName, updateBrandName };
      },
    };
    </script>
    

    10、组合API-ref属性

    获取DOM或者组件实例可以使用ref属性,写法和vue2.0需要区分开

    <template>
      <div class="container">
        <!-- vue2.0 获取div元素 -->
        <!-- 1. 通过ref属性绑定该元素 -->
        <!-- 2. 通过this.$ref.box获取元素 -->
        <!-- <div>我是box</div> -->
        <!-- vue2.0 获取v-for遍历多个元素 -->
        <!-- 1. 通过ref属性绑定被遍历元素 -->
        <!-- 2. 通过this.$ref.li 获取所有遍历元素(想取某一个用index取) -->
        <!-- <ul>
          <li v-for="i in 4" :key="i" ref="li">{{ i }}</li>
        </ul> -->
    
        <!-- 单个元素 -->
        <div ref="dom">我是box</div>
        <!-- 被遍历的元素 -->
        <ul>
          <li v-for="i in 4" :key="i" :ref="setDom">第{{ i }}LI</li>
        </ul>
      </div>
    </template>
    
    <script>
    import { ref, onMounted } from "vue";
    export default {
      name: "App",
      setup() {
        // 1.获取单个元素
        // 1.1 先定义一个空的响应式数据ref定义的
        // 1.2 setup中返回该数据,你想获取哪个dom元素,在该元素上使用ref属性绑定该数据即可
        const dom = ref(null);
        onMounted(() => {
          console.log(dom.value);
        });
    
        // 2.获取v-for遍历的元素
        // 2.1 定义一个空数组,接收所有的LI
        // 2.2 定义一个函数,往空数组push DOM
        const domList = [];
        const setDom = (el) => {
          domList.push(el);
        };
        console.log(domList);
        return { dom, setDom };
      },
    };
    </script>
    

    11、组合API-父子通讯

    <template>
      <div class="container">
        <h3>父组件</h3>
        <p>{{ money }}</p>
        <hr />
        <Son :money="money" @change-money="updateMoney" />
      </div>
    </template>
    
    <script>
    import { ref } from "vue";
    import Son from "./Son.vue";
    export default {
      name: "App",
      components: { Son },
      setup() {
        const money = ref(100);
        const updateMoney = (num) => {
          money.value = num;
        };
        return { money, updateMoney };
      },
    };
    </script>
    
    <template>
      <div class="container">
        <h3>子组件</h3>
        <p>{{ money }}</p>
        <button @click="changemoney">花50元</button>
      </div>
    </template>
    
    <script>
    import { onMounted, ref } from "vue";
    export default {
      name: "Son",
      // 子组件接受父组件数据使用props
      props: {
        money: {
          type: Number,
          default: 0,
        },
      },
      // props 父组件数据
      // emit 触发自定义事件的函数
      setup(props, { emit }) {
        // 获取父组件数据money
        console.log(props.money);
    
        // 向父组件传值
        const changemoney = () => {
          emit("change-money", 50);
        };
    
        return {
          changemoney,
        };
      },
    };
    </script>
    

    12、组合API-依赖注入

    <template>
      <div class="container">
        <h1>父组件 {{ money }} <button @click="money = 1000">发钱</button></h1>
        <hr />
        <Son />
      </div>
    </template>
    <script>
    import { provide, ref } from "vue";
    import Son from "./Son.vue";
    export default {
      name: "App",
      components: {
        Son,
      },
      setup() {
        const money = ref(100);
        const changeMoney = (saleMoney) => {
          console.log("changeMoney", saleMoney);
          money.value = money.value - saleMoney;
        };
        // 将数据提供给后代组件 provide
        provide("money", money);
        // 将函数提供给后代组件 provide
        provide("changeMoney", changeMoney);
    
        return { money };
      },
    };
    </script>
    <style scoped lang="less"></style>
    
    <template>
      <div class="container">
        <h2>子组件 {{ money }}</h2>
        <hr />
        <GrandSon />
      </div>
    </template>
    <script>
    import { inject } from "vue";
    import GrandSon from "./GrandSon.vue";
    export default {
      name: "Son",
      components: {
        GrandSon,
      },
      setup() {
        // 接收祖先组件提供的数据
        const money = inject("money");
        return { money };
      },
    };
    </script>
    <style scoped lang="less"></style>
    
    <template>
      <div class="container">
        <h3>孙组件 {{ money }} <button @click="fn">消费20</button></h3>
      </div>
    </template>
    <script>
    import { inject } from "vue";
    export default {
      name: "GrandSon",
      setup() {
        const money = inject("money");
        // 孙组件,消费50,通知父组件App.vue组件,进行修改
        // 不能自己修改数据,遵循单选数据流原则,大白话:数据谁定义谁修改
        const changeMoney = inject("changeMoney");
        const fn = () => {
          changeMoney(20);
        };
        return { money, fn };
      },
    };
    </script>
    <style scoped lang="less"></style>
    
    

    13、补充-v-model语法糖

    在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />

    在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

    <template>
      <div class="container">
        <!-- 如果你想获取原生事件事件对象 -->
        <!-- 如果绑定事函数 fn fn(e){ // e 就是事件对象 } -->
        <!-- 如果绑定的是js表达式  此时提供一个默认的变量 $event -->
        <h1 @click="$event.target.style.color = 'red'">父组件 {{ count }}</h1>
        <hr />
        <!-- 如果你想获取自定义事件  -->
        <!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } -->
        <!-- 如果绑定的是js表达式  此时 $event代表触发自定义事件的传参 -->
        <!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
        <Son v-model="count" />
      </div>
    </template>
    <script>
    import { ref } from "vue";
    import Son from "./Son.vue";
    export default {
      name: "App",
      components: {
        Son,
      },
      setup() {
        const count = ref(10);
        return { count };
      },
    };
    </script>
    
    <template>
      <div class="container">
        <h2>子组件 {{ modelValue }} <button @click="fn">改变数据</button></h2>
      </div>
    </template>
    <script>
    export default {
      name: "Son",
      props: {
        modelValue: {
          type: Number,
          default: 0,
        },
      },
      setup(props, { emit }) {
        const fn = () => {
          // 改变数据
          emit("update:modelValue", 100);
        };
        return { fn };
      },
    };
    </script>
    
    

    总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue

    补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx 子传父 @update:xxx 在vue3.0 使用 v-model:xxx 代替。

    14、补充-mixins语法

    混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

    全局混入

    // main.js
    import { createApp } from 'vue';
    import App from './App.vue';
    const app = createApp(App);
    // vue2.0 Vue.mixin({ 全局混入的选项对象 })
    // vue3.0 app.mixin({ 全局混入的选项对象 })
    app.mixin({
        // 在任何组件 dom准备好的时候 打印一句话
        methods: {
            say() {
                console.log(this.$el,'dom准备好了');
            }
        },
        mounted() {
            this.say();
        }
    })
    app.mount('#app');
    

    局部混入

    // mixins.js
    // 配置对象
    export const followMixin =  {
        data () {
          return {
            loading: false
          }
        },
        methods: {
          followFn () {
            this.loading = true
            // 模拟请求
            setTimeout(()=>{
              // 省略请求代码
              this.loading = false
            },2000)
          }
        }
    }
    
    <template>
      <div class="container1">
        <h1>
          作者:周杰伦
          <a href="javascript:;" @click="followFn">{{ loading ? "请求中..." : "关注" }}</a>
        </h1>
        <hr />
        <Son />
      </div>
    </template>
    <script>
    import Son from "./Son.vue";
    import { followMixin } from "./mixins.js";
    export default {
      name: "App",
      components: {
        Son,
      },
      mixins: [followMixin],
    };
    </script>
    
    <template>
      <div class="container2">
        <h2>
          作者:周杰伦
          <button @click="followFn">{{ loading ? "loading..." : "关注" }}</button>
        </h2>
      </div>
    </template>
    <script>
    import { followMixin } from "./mixins.js";
    export default {
      name: "Son",
      mixins: [followMixin],
    };
    </script>
    <style scoped lang="less"></style>
    

    15、vuex

    全局使用方法

    import { createStore } from 'vuex'
    
    // vue2.0 创建仓库 new Vuex.Store({})
    // vue3.0 创建仓库 createStore({})
    export default createStore({
      state: {
        username: 'zs'
      },
      getters: {
        newName(state) {
          return state.username + '!!!'
        }
      },
      mutations: {
        updateName(state, payload) {
          state.username = payload
        }
      },
      actions: {
        updateName(ctx) {
          // 发送请求
          setTimeout(() => {
            ctx.commit('updateName', 'ls')
          }, 1000)
        }
      },
      modules: {
      }
    })
    
    <template>
      <div>
        App
        <!-- 1.使用根模块的数据 -->
        <p>{{ $store.state.username }}</p>
        <!-- 2.使用根模块getters的数据 -->
        <p>{{ $store.getters.newName }}</p>
        <button @click="mutationsFn">mutationsFn</button>
      </div>
    </template>
    <script>
    import { useStore } from 'vuex'
    export default {
      name: 'App',
      setup() {
        // 使用vuex仓库
        const store = useStore()
        // 1.使用根模块state的数据
        console.log(store.state.username)
        // 2.使用根模块getters的数据
        console.log(store.getters.newName)
    
        const mutationsFn = () => {
          // 3.提交根模块的mutations函数
          // store.commit('updateName', 'ls')
          // 4.调用根模块actions函数
          store.dispatch('updateName')
        }
    
        return { mutationsFn }
      }
    }
    </script>
    

    分模块使用

    • 存在两种情况
      • 默认的模块,state 区分模块,其他 getters mutations actions 都在全局。
      • 带命名空间 namespaced: true 的模块,所有功能区分模块,更高封装度和复用。
    import { createStore } from 'vuex'
    
    // A模块
    const moduleA = {
      state: {
        username: 'moduleA'
      },
      getters: {
        newName(state) {
          return state.username + '!!!'
        }
      },
      mutations: {
        updateName(state) {
          state.username = 'moduleAAAAAA'
        }
      }
    }
    
    // B模块
    const moduleB = {
      namespaced: true,
      state: {
        username: 'moduleB'
      },
      getters: {
        newName(state) {
          return state.username + '!!!'
        }
      },
      mutations: {
        updateName(state, payload) {
          state.username = payload
        }
      },
      actions: {
        updateName(ctx) {
          // 发送请求
          setTimeout(() => {
            ctx.commit('updateName', 'zs')
          }, 1000)
        }
      }
    }
    
    export default createStore({
      modules: {
        moduleA,
        moduleB
      }
    })
    
    <template>
      <div>
        <!-- moduleA -->
        <!-- 1.1 使用A模块的state数据 -->
        <p>{{ $store.state.moduleA.username }}</p>
        <!-- 1.2 使用A模块的getters数据 -->
        <p>{{ $store.getters.newName }}</p>
    
        <!-- moduleB -->
        <!-- 2.1 使用B模块的state数据 -->
        <p>{{ $store.state.moduleB.username }}</p>
        <!-- 2.2 使用B模块的getters数据-->
        <p>{{ $store.getters['moduleB/newName'] }}</p>
        <button @click="mutationsFn">mutationsFn</button>
        <button @click="actionsFn">actionsFn</button>
      </div>
    </template>
    <script>
    import { useStore } from 'vuex'
    export default {
      name: 'App',
      setup() {
        const store = useStore()
        const mutationsFn = () => {
          // 2.3 提交B模块的修改
          store.commit('moduleB/updateName', 'ls')
        }
        const actionsFn = () => {
          // 2.4 调用B模块的actions
          store.dispatch('moduleB/updateName')
        }
        return {
          mutationsFn,
          actionsFn
        }
      }
    }
    </script>
    

    16、vuex持久化插件

    • npm i vuex-persistedstate

    • store 里面配置

      import { createStore } from 'vuex'
      +import createPersistedstate from 'vuex-persistedstate'
      
      import user from './modules/user'
      import cart from './modules/cart'
      import category from './modules/category'
      
      export default createStore({
        modules: {
          user,
          cart,
          category
        },
      +  plugins: [
      +    createPersistedstate({
      +      key: 'erabbit-client-pc-store',
      +      paths: ['user', 'cart']
      +    })
      +  ]
      })
      
    • 使用

      // 用户模块
      export default {
        namespaced: true,
        state () {
          return {
            // 用户信息
            profile: {
              id: '',
              avatar: '',
              nickname: '',
              account: '',
              mobile: '',
              token: ''
            }
          }
        },
        mutations: {
          // 修改用户信息,payload就是用户信息对象
          setUser (state, payload) {
            state.profile = payload
          }
        }
      }
      
    <template>
      <div class="container">
        <!-- 修改数据,测试是否持久化 -->
        App {{ $store.state.user.profile.account }}
        <button @click="$store.commit('user/setUser', { account: 'zhousg' })">
          设置用户信息
        </button>
      </div>
    </template>
    <script>
    export default {
      name: 'App'
    }
    </script>
    

    相关文章

      网友评论

          本文标题:vue3基本使用

          本文链接:https://www.haomeiwen.com/subject/gediprtx.html