vue3学习随便记2(代码片段)

sjg20010414 sjg20010414     2022-12-13     573

关键词:

引子

初步学习 Vue的概念,一上来就用 vue-cli 的方式的确是找死,会让自己陷入很多复杂的坑。初次尝试,最好是直接引入。

在开始了解 Vue 的概念之前,我们要先来回顾一下 MVC模式、MVVM模式的初步思想。

MVC 模式是一种后端考虑思维,是厚重后端的思维。Model负责对来自用户的数据、从数据库获取的数据进行加工,有关业务逻辑的处理,把一定的数据通过Controller提供给 View 层。View 层负责利用所给的数据生成展示用的 HTML、CSS、JS 发送给客户浏览器,如果需要一些前端的效果,则在 JS 中通过操作 DOM 实现。Controller 层是很瘦的连接器,负责沟通 View 和 Model。当然,Controller 层是用户端的第一入口,所以往往和路由有关。MVC思维中,用户界面view上的变化都是事件(例如点击了某个链接,提交了表单),我们针对每个事件写代码(对应controller中的action),把用户输入转换到model中处理。

MVVM模式是一种前后端分离的思维,是厚重前端的思维。前后端分离后,后端只是扔一堆数据给前端,后面的事(呈现逻辑)都是前端的事。Model 从前端看就是API请求获得数据,View就是单纯的 HTML、CSS 展示,大量的呈现逻辑都是 ViewModel 负责(ViewModel是专门为View服务的Model,即View的数据对象)。MVVM思维中,view里面的各种控件有一个对应的数据对象,这样,只要修改这个数据对象,view里面显示的内容就自动同步刷新,反之,view里面做了任何操作,这个数据对象也跟着同步修改,这些功能的实现都是底层处理的,开发者不用直接操作DOM。

在 MVC 中,View需要呈现的东西具体数据是怎样的,还是需要较多和后端联系,起码有详细文档说明。而 MVVM 中,View 设计者可以关注设计,关于数据和事件,就是一堆声明,它面向ViewModel中的数据即可。ViewModel开发者可以来协调怎么从后台获取数据,怎么调整成更适合View的数据,换句话说,View和Model解耦了。在 MVVM 下,组件的可复用性更强。

MVVM中的bug调试比MVC中的要困难一些(前端调试本就比较困难),压力也主要在浏览器一侧,大的 ViewModel 构建和维护的成本也比较高。某种程度上,MVVM模式下的SPA应用,基本上和传统的C/S风格的窗口程序无异了。静态内容偏多的网站,可能用 MVVM 没有多少优势,而典型的业务型 SPA 才是能体现它优点的地方。

MVVM的主要魔法是 数据劫持、数据代理、数据编译和“发布订阅模式”。

数据劫持:主要是给对象的(data中的那些)属性添加 get、set 钩子函数。

数据代理:把 data、methods、computed 上的数据挂载到 vm 实例上,这些地方定义的数据,就都是vm实例的数据,从而不用 vm._data.a.b 这样去访问,直接用 vm.a.b 即可。

数据编译:把 ,v-model,v-html,v-on 里面的对应的变量用 data 里面的数据进行替换。

发布订阅:订阅就是将订阅者添加到订阅队列中,发布就是让订阅者得到调用执行。所谓订阅者,就是函数,订阅队列,就是数组。在数据发生改变的时候,订阅者收到通知,执行相应的操作。一般 get 钩子函数被调用时进行数据的订阅,在 set 钩子函数被调用时进行数据的发布。

双向绑定主要是数据劫持和发布订阅模式的作用。

介绍

声明式渲染

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="counter">
        计数器:  counter 
    </div>
    <script>
        const Counter = 
            data() 
                return 
                    counter: 0
                
            ,
            mounted() 
                setInterval(() => 
                    this.counter++
                , 1000)
            
        
        Vue.createApp(Counter).mount('#counter')
    </script>
</body>

</html>

Vue.createApp 根据 Counter 定义的数据对象配置创建数据对象vm(相当于ViewModel),然后用 mount 方法和 DOM建立关联。数据和DOM建立关联后,所有东西都是响应式的。

data() 返回的对象,其中的键值对直接成为vm的数据(数据代理),之所以插一层 data(),这里意味着 data()内的数据都是vm的被“监视”的变量,一旦这些变量改变,(订阅者收到通知)背后相应的方法调用,该替换修改的地方得到修改(模板编译)。

不仅文本插值可以实现响应式替换,元素的属性也可以绑定到变量,响应式自动替换。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="bind-attribute">
        <span v-bind:title="message">
            鼠标悬停几秒钟查看此处动态绑定的提示消息!
        </span>
    </div>
    <script>
        const AttributeBinding = 
            data() 
                return 
                    message: '你加载此页的时间 ' + new Date().toLocaleString()
                
            ,
            mounted() 
                setInterval(() => 
                    this.counter++
                , 1000)
            
        
        Vue.createApp(AttributeBinding).mount('#bind-attribute')
    </script>
</body>

</html>

处理用户输入

用户输入包括在文本框之类的东西输入数据,也包括点击按钮之类的动作。可以用 v-on 指令添加事件监听器,绑定到vm的实例方法。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="event-handling">
        <p> message </p>
        <button v-on:click="reverseMessage">反转 消息文本</button>
    </div>
    <script>
        const EventHandling = 
            data() 
                return 
                    message: 'Hello Vue3'
                
            ,
            methods: 
                reverseMessage() 
                    this.message = this.message.split('').reverse().join('')
                
            
        
        Vue.createApp(EventHandling).mount('#event-handling')
    </script>
</body>

</html>

用 Vue 提供的 v-model 指令,可以将表单输入和vm变量之间双向绑定,用户输入可以被自动get到并同步到变量,变量被修改时也可以自动反映到表单输入。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="two-way-binding">
        <p> message </p>
        <input v-model="message" />
    </div>
    <script>
        const TwoWayBinding = 
            data() 
                return 
                    message: 'Hello Vue3'
                
            
        
        Vue.createApp(TwoWayBinding).mount('#two-way-binding')
    </script>
</body>

</html>

 条件与循环

条件控制就是一个元素是否显示的控制,是否显示包含是否渲染(v-if)和渲染后是否隐藏(v-show)。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="conditional-rendering">
        <div>
            <span v-if="seen">这个渲染了</span> <br>
            <span v-show="show">这个显示了</span>
        </div>
        <div>
            <button @click="toggleSeen">切换渲染的</button>
            <button @click="toggleShow">切换显示</button>
        </div>
    </div>
    <script>
        const ConditionalRendering = 
            data() 
                return 
                    seen: true,
                    show: true
                
            ,
            methods: 
                toggleSeen() 
                    this.seen = !this.seen
                ,
                toggleShow() 
                    this.show = !this.show
                
            
        
        Vue.createApp(ConditionalRendering).mount('#conditional-rendering')
    </script>
</body>

</html>

我们点击按钮,让两个文本都看不到,再观察实际的HTML元素,可以发现,同样是隐藏,v-if 是不渲染,v-show 是渲染而不显示

 

对于数组数据的显示,可以用 v-for 指令绑定数组数据来渲染,循环显示成列表或其他相同的块。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="list-rendering">
        <ol>
            <li v-for="todo in todos">
                 todo.text 
            </li>
        </ol>
    </div>
    <script>
        const ListRendering = 
            data() 
                return 
                    todos: [
                         text: 'Learn JavaScript' ,
                         text: 'Learn Vue' ,
                         text: 'Build something awesome' 
                    ]
                
            
        
        Vue.createApp(ListRendering).mount('#list-rendering')
    </script>
</body>

</html>

可以将可复用的,或者功能相对独立的块构建为独立的组件,以便提高复用效果或可维护性。

<html>

<head>
    <script src="vue.global.js"></script>
</head>

<body>
    <div id="list-rendering">
        <ol>
            <todo-item v-for="todo in todos"></todo-item>
        </ol>
    </div>
    <script>
        const TodoItem = 
            template: `<li>这是一个待办事项</li>`
        
        const TodoList = 
            components: 
                TodoItem
            ,
            data() 
                return 
                    todos: [
                         text: 'Learn JavaScript' ,
                         text: 'Learn Vue' ,
                         text: 'Build something awesome' 
                    ]
                
            
        
        Vue.createApp(TodoList).mount('#list-rendering')
    </script>
</body>

</html>

我们用声明式数据对象定义了组件

        const TodoItem = 
            template: `<li>这是一个待办事项</li>`
        

然后在 TodoList 数据对象中注册了该组件 (TodoList 的 components 属性)

            components: 
                TodoItem
            ,

然后在 TodoList 的 view 中使用该组件 (把它当作新元素)

<todo-item v-for="todo in todos"></todo-item>

最后的效果是

这样不能合乎逻辑,我们希望组件 TodoItem 渲染出来的是 todos 数组中的数据。我们必须有一种机制,可以让组件 TodoItem 这个儿子,能够接受父亲 TodoList 传给它的数据,并渲染出来。实现这一通信的是属性机制,我们修改注册组件部分,使组件包含 todo 属性,并且渲染的文本是该属性的 text 键值 todo.text

        const TodoItem = 
            props: ['todo'],
            template: `<li> todo.text </li>`
        

在使用组件时,把数据绑定到该属性(数据item----->属性todo)

        <ol>
            <todo-item v-for="item in todos"
                v-bind:todo="item"
            ></todo-item>
        </ol>

现在效果就是

 事实上,每个应用都有一个组件,即根组件,在上述例子中就是 TodoList 根组件,根组件下可以有子组件。我们尝试用 vue的 devtools 浏览器插件来查看,先要处理该插件,鉴于翻墙太麻烦,我们从 devtools 源码开始

git clone https://github.com/vuejs/devtools.git        // 克隆源码
cd devtools
yarn                        // 安装依赖
yarn build                    // 构建

然后 packages 子目录下有生成的各种适用于浏览器的东西,关注 shell-chrome 子目录,将它作为解压缩的扩展加载到 Edge 浏览器。重新启动浏览器加载前述页面,F12打开开发人员工具,选择 Vue tab页,可以看到如下页面结构:

 Vue应用页面总是一棵 DOM树,这里是最简单的,类似如下

 

vue3学习随便记1(代码片段)

安装|Vue.js官网文档提到4种安装方式:在页面CDN包的形式导入下载JavaScript文件放到自己网站再引入使用npm安装使用官方cli构建项目除了第3种,似乎我都稍微用过一下,第1、2种方式是在网站的局部使用vue(第一种... 查看详情

vue3学习随便记1(代码片段)

安装|Vue.js官网文档提到4种安装方式:在页面CDN包的形式导入下载JavaScript文件放到自己网站再引入使用npm安装使用官方cli构建项目除了第3种,似乎我都稍微用过一下,第1、2种方式是在网站的局部使用vue(第一种... 查看详情

vue3学习随便记7(代码片段)

事件处理监听事件其实我们已经用了不少监听事件,即v-on:click="methodName"(简写为@click="methodName")事件处理方法事件处理总是对应一个方法,直接写JS代码作为事件处理是不行的。<html><... 查看详情

vue3学习随便记10(代码片段)

深入组件自定义事件事件名规则和组件prop一样,即JS中camelCase,HTML中kebab-case。this.$emit('myEvent')<my-component@my-event="doSomething"></my-component>自定义事件在组件的emits选项上定义。如果在 查看详情

vue3学习随便记8(代码片段)

...用template定义的字符串模板。这样的组件主要用来举例和学习原理,实际工程中通常会使用单文件组件,即一个组件是单个文件定义的(在编译构建系统中常常是.vue文件)。组件是自定义元素 查看详情

vue3学习随便记3(代码片段)

应用实例与组件实例创建一个应用实例创建应用实例是通过全局API函数createApp实现的,应用有它自己的应用API函数,并且应用API函数的返回值多数是应用自己,所以,可以链式调用<html><head><scriptsrc=&... 查看详情

vue3学习随便记5(代码片段)

计算属性和侦听器计算属性计算属性可以避免在模板中放入复杂逻辑,维持模板的清晰。计算属性像属性一样被使用,但可能依赖其他属性,而且它是响应式的。<html><head><scriptsrc="vue.global.js"><... 查看详情

vue3学习随便记3(代码片段)

应用实例与组件实例创建一个应用实例创建应用实例是通过全局API函数createApp实现的,应用有它自己的应用API函数,并且应用API函数的返回值多数是应用自己,所以,可以链式调用<html><head><scriptsrc=&... 查看详情

vue3学习随便记5(代码片段)

计算属性和侦听器计算属性计算属性可以避免在模板中放入复杂逻辑,维持模板的清晰。计算属性像属性一样被使用,但可能依赖其他属性,而且它是响应式的。<html><head><scriptsrc="vue.global.js"><... 查看详情

vue3学习随便记4(代码片段)

模板语法插值文本插值:插值Mustache语法,会将数据解释为普通文本<span>Message:msg</span>组件实例msgproperty改变时,插值内容自动改变。如果希望插值处的内容只被替换一次,可以附加使用v-once指令<spanv-on... 查看详情

vue3学习随便记4(代码片段)

模板语法插值文本插值:插值Mustache语法,会将数据解释为普通文本<span>Message:msg</span>组件实例msgproperty改变时,插值内容自动改变。如果希望插值处的内容只被替换一次,可以附加使用v-once指令<spanv-on... 查看详情

vue3学习随便记9(代码片段)

深入组件组件注册注册组件时必须给组件命名。组件名的命名规则和组件要使用在哪里有关,如果只是要混在DOM中使用组件,那名字应该全部小写,多个单词用连字符连接(即kebab-case),这样可以避免与HT... 查看详情

vue3学习随便记11(代码片段)

深入组件Provide/Inject通常,我们需要把数据从父组件向子组件传递时,使用prop。但对于深度嵌套的组件系统,有时候,深层子组件需要父组件的部分内容,此时,仍然使用prop机制会非常麻烦。例如,爷... 查看详情

vue3学习随便记7(代码片段)

事件处理监听事件其实我们已经用了不少监听事件,即v-on:click="methodName"(简写为@click="methodName")事件处理方法事件处理总是对应一个方法,直接写JS代码作为事件处理是不行的。<html><... 查看详情

vue3学习随便记10(代码片段)

深入组件自定义事件事件名规则和组件prop一样,即JS中camelCase,HTML中kebab-case。this.$emit('myEvent')<my-component@my-event="doSomething"></my-component>自定义事件在组件的emits选项上定义。如果在emits选项中定... 查看详情

vue3学习随便记13(代码片段)

过渡与动画进入过渡和离开过渡在插入、更新或从DOM移除项时,Vue提供了多种方法实现转换效果:自动为CSS过渡和动画应用class集成第三方CSS动画库,例如 Animate.css|Across-browserlibraryofCSSanimations.在过渡钩子期间使用JS... 查看详情

vue3学习随便记13(代码片段)

过渡与动画进入过渡和离开过渡在插入、更新或从DOM移除项时,Vue提供了多种方法实现转换效果:自动为CSS过渡和动画应用class集成第三方CSS动画库,例如 Animate.css|Across-browserlibraryofCSSanimations.在过渡钩子期间使用JS... 查看详情

vue3学习随便记12(代码片段)

过渡与动画Vue提供了一些抽象概念,可以帮助处理过渡和动画:组件进入DOM和离开DOM的钩子,在CSS和JS均可用,使用内置组件<transition>过渡模式,在过渡期间编排顺序处理多个元素就地更新的钩子,使... 查看详情