vue.js基础02--computed、watch、methods区别、自定义组件components及组件其他使用细节

一、computed、watch、methods

1.vue实例中的计算属性选项

计算属性关键词: computed。

在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。注意:computed定义的名称不能与data一样

<body>
<div id="example">
    <p>Original message: "{{ message }}"</p>
    <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</body>
<!--将vue引入到本地-->
<script src="js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#example',
        data: {
            message: 'Hello'
        },
        computed: {
        // 计算属性的 getter
            reversedMessage: function () {
        // `this` 指向 vm 实例
                return this.message.split('').reverse().join('')
            }
        }
    })
</script>

computed vs methods

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于data的依赖缓存,只有相关依赖状态发生改变时会重新计算,页面重新渲染值不会变化。而使用 methods ,在重新渲染的时候,函数总会重新调用执行(即调用就执行)

<body>
<div id="example">
    <p>Original message: "{{ message }}"</p>
    <p>Computed reversed message: "{{ reversedMessage }}"</p>
    <p >Methods reversed message: "{{ reversedMessage2() }}"</p>
</div>
</body>
<!--将vue引入到本地-->
<script src="js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#example',
        data: {
            message: 'Hello'
        },
        computed: {
        // 计算属性的 getter
            reversedMessage: function () {
        // `this` 指向 vm 实例
                return this.message.split('').reverse().join('')
            }
        },
        //通过方法来惭怍属性
        methods:{
            reversedMessage2:function () {
                return this.message.split('').reverse().join('')
            }
        }
    })
</script>

2. watch

vue.js提供了一个方法$watch(也存在缓存机制,但是没computed简洁),用于观察Vue实例上的数据变动。更好的办法是使用计算属性而不是一个命令式的$watch回调。

说白了$watch这货就是观察一个值的变化,观察的这个值一变化的话,那么就执行function里面的语句。数据变化时执行异步或开销较大的操作

watch是在vue实例对象中观测数据的变化;$watch是通过实例对象调用观测数据。

<div id="example">
    firstName:<input type="text" name="li"  v-model="firstName">
             <br>
    lastName:<input type="text" name="fei"  v-model="lastName">
    <p>fullName: {{fullName}}</p>
</div>
</body>
<!--将vue引入到本地-->
<script src="js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#example',
        data: {
            firstName:'Foo',
            lastName:'Bar',
            fullName:''
        },
        computed: {
        // 计算属性的 getter
            reversedMessage: function () {
        // `this` 指向 vm 实例
                return this.message.split('').reverse().join('')
            }
        },
        //通过方法来惭怍属性
        methods:{
            reversedMessage2:function () {
                return this.message.split('').reverse().join('')
            }
        },
//        watch: {
//             firstName: function (val) {
//                 this.fullName = val + ' ' + this.lastName
//             },
//            lastName: function (val) {
//                this.fullName = this.firstName + ' ' + val
//            }
//        }
    });
    vm.$watch('lastName',function (val) {
        this.fullName = val+' '+this.lastName;
    });
    vm.$watch('firstName',function (val) {
        this.fullName = this.firstName+' '+val;
    })
</script>

1.1 computed

    1.是计算值
    2.具有缓存性,页面重新渲染值不会变化,计算属性会立即返回之前的计算结果,而不必再次执行函数(只有当依赖数据发生改变才会重新计算)
    3.不支持异步,当computed内有异步操作时无效,无法监听数据的变化

    4.不支持箭头函数

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上,使用箭头函数打印this,发现是undefined。
        箭头函数的this是定义时就固定的,不能改变或者重新绑定;而普通函数的this,是指向运行时所在的作用域,所以是可以改变或重新绑定。

2.2 watch

    1.是观察的动作

    2.无缓存性,页面重新渲染时值不变化也会执行(值改变则直接触发)

    3.支持异步

    4.监听数据必须是 data 中声明过或者父组件传递过来的props中的数据以及挂载到vm上的数据(computed)

    5.不支持箭头函数

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上。

2.3 methods

    1.是函数

    2.无缓存性,页面重新渲染会被重新调用

    3.支持异步

    4.不支持箭头函数

        理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,我们这里需要挂载到vm上。

下面还另外总结了几点关于 computed 、watch 和 methods 的差异:

  1. computed 是计算一个新的属性,并将该属性挂载到 vm(Vue 实例)上,而 watch 是监听已存在且已挂载到 vm 上的数据,所以用 watch 同样可以监听 computed 计算属性的变化(其它还有 dataprops
  2. computed 本质是一个惰性求值的观察者,具有缓存性,只有当依赖变化后,第一次访问 computed 属性,才会计算新的值,其他直接使用这个计算得到的值,而 watch 则是当数据发生变化便会调用执行函数
  3. 计算属性是有缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行
  4. methods 则是调用才更新
  5. 从使用场景上说,computed 适用一个数据被多个数据影响,而 watch 适用一个数据影响多个数据

二、vue 组件

2.Vue.js 组件

组件(Component)是 Vue.js 最强大的功能之一。

组件可以扩展 HTML 元素,封装可重用的代码。

组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树

注册一个全局组件语法格式如下:

Vue.component(tagName, options)

tagName 为组件名(标签名),options 为配置选项。注册后,我们可以使用以下方式来调用组件:

<tagName></tagName>
<div id="example">
    <!--使用我们自定义的组件-->
    <goheader></goheader>
</div>
</body>
<!--将vue引入到本地-->
<script src="js/vue.js"></script>
<script>
//    注册一个全局组件
    Vue.component('goheader',{
        template:'<h2>自定义全局组件!</h2>'
    });
    var vm = new Vue({
        el: '#example',
        data: {
//            这里不能将全局组件中的数组定义在data中
//           meg:"自定义全局组件!"
        }
    })
</script>

局部组件

我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:

<div id="example">
    <!--使用我们自定义的组件-->
    <go-child></go-child>
</div>
</body>
<!--将vue引入到本地-->
<script src="js/vue.js"></script>
<script>
//    注册一个局部模板
    var divChild = {
        template:'<h2>自定义局部组件!</h2>'
    };
    var vm = new Vue({
        el: '#example',
        //注册组件的选型
        components:{
            //<go-child>只在父模板中使用
            'goChild':divChild
        }
    })
</script>

动态组件:(:is="组件名")

不改变路由的情况下切换不同的页面/组件

// 子组件占位符
<component :is="viewCom"></component>

vue-动态组件(:is=“组件名“)_muzidigbig的博客-CSDN博客_vue动态组件名

组件使用细节

1.组件is的用法

<ul><ol><table><select> 这样的元素里允许包含的元素有限制,而另一些像这样的元素只能出现在某些特定元素的内部。在自定义组件中使用这些受限制的元素时会导致一些问题,例如:

// 会展示不出我们的子组件my-row
<table>
  <my-row>...</my-row>
</table>

自定义组件 <my-row> 会被当作无效的内容,因此会导致错误的渲染结果。变通的方案是使用特殊的 is 特性:

<table>
  <tr is="my-row"></tr>
</table>

应当注意,如果使用来自以下来源之一的字符串模板,则没有这些限制:

  • <script type="text/x-template">
  • JavaScript 内联模板字符串
  • .vue 组件

因此,请尽可能使用字符串模板。

这就用到了本文的中心“is”,当我们使用<tr is="my-tr" v-for="(man,key) in mans" :man="man" :key="key"></tr>引入插件,而不是<my-tr></my-tr>时,一切就正常了。

2.cli中组件,data必须是函数,并且返回一个对象,在对象内部保存数据

vue组件中data必须是一个函数的原因_muzidigbig的博客-CSDN博客

理解这点之后,再理解js的原型链:  

var MyComponent = function() {}
MyComponent.prototype.data = { a: 1, b: 2,}
  // 上面是一个虚拟的组件构造器,真实的组件构造器方法很多  
var component1 = new MyComponent()
var component2 = new MyComponent()
// 上面实例化出来两个组件实例,也就是通过 MyComponent  调用,创建的两个实例
component1.data.a === component2.data.a // true
component1.data.b = 5
component2.data.b // 5 

  可以看到上面代码中最后三句,这就比较坑爹了,如果两个实例同时引用一个对象,那么当你修改其中一个属性的时候,另外一个实例也会跟着改。这怎么可以,两个实例应该有自己各自的域才对。所以,需要通过下面方法来进行处理:  

var MyComponent = function() {
    this.data = this.data()
}
MyComponent.prototype.data = function() { return { a: 1, b: 2, }  }  

这样每一个实例的data属性都是独立的,不会相互影响了。
3.组件,ref获取dom/子组件实例对象

ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向该子组件实例

通俗的讲,ref特性就是为元素或子组件赋予一个ID引用,通过this.$refs.refName来访问dom元素或子组件的实例对象

<p ref="p">Hello</p>
<children ref="children"></children>
this.$refs.p; // dom
this.$refs.children // 子组件实例

this.$refs介绍

this.$refs 是一个对象,持有当前组件中注册过 ref 特性的所有 DOM 元素和子组件实例对象

注意: $refs只有在组件渲染完成后才填充,在初始渲染的时候不能访问它们,并且它是非响应式的,因此不能用它在模板中做数据绑定。

若有不足请多多指教!希望给您带来帮助!

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,那就让我们来一步步实现一个简单的Vue小作品吧。我们可以实现一个简单的待办事项应用,用户可以添加待办事项、标记已完成的事项、删除待办事项等功能。这个应用将会用到Vue数据绑定、组件、路由等技术。我们先来安装Vue和Vue CLI。 1. 安装Vue和Vue CLI 首先,你需要在本地安装Node.js和npm。然后,在命令行中运行以下命令安装Vue CLI: ``` npm install -g @vue/cli ``` 安装完成后,你可以在命令行中运行以下命令创建一个新的Vue项目: ``` vue create my-todo-app ``` 根据提示选择你需要的配置,Vue CLI 将会自动生成一个基础的 Vue 项目。 2. 创建一个待办事项组件 接下来,我们要创建一个待办事项组件。在项目根目录下的 `src/components` 中创建一个新的文件 `TodoItem.vue`。在这个文件中,我们将创建一个单个待办事项的组件。 ```html <template> <div class="todo-item"> <input type="checkbox" v-model="todo.completed" @change="toggleCompleted"> <span :class="{ 'completed': todo.completed }">{{ todo.text }}</span> <button @click="$emit('remove')">删除</button> </div> </template> <script> export default { props: ['todo'], methods: { toggleCompleted() { this.$emit('toggle', this.todo.id); } } } </script> <style> .completed { text-decoration: line-through; } </style> ``` 在这个组件中,我们有一个单选框来标记待办事项是否已经完成,如果待办事项已经完成,它的文本将会有删除线。我们还有一个删除按钮来删除待办事项。 3. 创建一个待办事项列表组件 接下来,我们要创建一个待办事项列表组件,它将会用来显示所有的待办事项。在项目根目录下的 `src/components` 中创建一个新的文件 `TodoList.vue`: ```html <template> <div class="todo-list"> <div v-for="todo in filteredTodos" :key="todo.id"> <TodoItem :todo="todo" @toggle="toggleTodo" @remove="removeTodo"></TodoItem> </div> </div> </template> <script> import TodoItem from './TodoItem.vue'; export default { components: { TodoItem }, props: ['todos'], computed: { filteredTodos() { return this.todos.filter(todo => { return !this.showCompleted || todo.completed === false; }); } }, data() { return { showCompleted: false }; }, methods: { toggleTodo(id) { const todo = this.todos.find(todo => todo.id === id); todo.completed = !todo.completed; }, removeTodo() { this.$emit('remove'); } } } </script> <style> .todo-list { margin-top: 20px; } </style> ``` 在这个组件中,我们使用了 `v-for` 指令来循环渲染每一个待办事项。我们还引入了之前创建的待办事项组件 `TodoItem`。我们还有一个切换已完成待办事项的开关。 4. 创建一个添加待办事项的组件 现在,我们要创建一个添加待办事项的组件。在项目根目录下的 `src/components` 中创建一个新的文件 `AddTodo.vue`: ```html <template> <div class="add-todo"> <input type="text" v-model="newTodo" placeholder="添加新的待办事项"> <button @click="addTodo">添加</button> </div> </template> <script> export default { data() { return { newTodo: '' }; }, methods: { addTodo() { if (this.newTodo) { this.$emit('add', this.newTodo); this.newTodo = ''; } } } } </script> <style> .add-todo { margin-top: 20px; } </style> ``` 在这个组件中,我们有一个文本输入框和一个添加按钮。当用户点击添加按钮时,我们将会触发一个事件来添加新的待办事项。 5. 创建一个根组件 最后,我们要创建一个根组件,它将会包含所有的子组件,并且处理待办事项的数据和状态。在项目根目录下的 `src` 中创建一个新的文件 `App.vue`: ```html <template> <div class="app"> <h1>待办事项</h1> <AddTodo @add="addTodo"></AddTodo> <div v-if="todos.length"> <TodoList :todos="todos" @remove="removeTodo"></TodoList> <div> <label> <input type="checkbox" v-model="showCompleted"> 显示已完成 </label> </div> </div> <div v-else> 没有待办事项 </div> </div> </template> <script> import TodoList from './components/TodoList.vue'; import AddTodo from './components/AddTodo.vue'; export default { components: { TodoList, AddTodo }, data() { return { todos: [], showCompleted: false, nextId: 1 }; }, methods: { addTodo:text=> { this.todos.push({ id: this.nextId++, text, completed: false }); }, removeTodo() { this.todos = this.todos.filter(todo => !todo.completed); } } } </script> <style> .app { max-width: 600px; margin: 0 auto; padding: 20px; font-family: 'Arial'; } </style> ``` 在这个组件中,我们引入了之前创建的添加待办事项组件和待办事项列表组件。我们还有一个 `data` 对象来存储待办事项的数据和状态。我们还有一些方法来添加、删除和切换待办事项的状态。 6. 添加路由 最后,我们要添加路由来让用户能够访问我们的待办事项应用。在项目根目录下的 `src` 中创建一个新的文件 `router.js`: ```js import Vue from 'vue'; import VueRouter from 'vue-router'; import App from './App.vue'; Vue.use(VueRouter); const routes = [ { path: '/', name: 'home', component: App } ]; const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }); export default router; ``` 在这个文件中,我们首先引入了 Vue 和 Vue Router,并使用 Vue.use 注册 Vue Router。我们还定义了一个路由对象,它将会指向我们的根组件。最后,我们创建了一个 VueRouter 实例,并把路由对象传递进去。 7. 启动应用 到这里,我们的待办事项应用已经完成了。现在,我们可以在命令行中运行以下命令启动应用: ``` npm run serve ``` 应用将会运行在 http://localhost:8080 上,你现在可以在浏览器中访问它了。如果你想要构建一个生产环境的应用,可以运行以下命令: ``` npm run build ``` 这个命令将会生成一个可以部署的静态文件,你可以将它部署到任何能够托管静态文件的地方。 以上是一个简单的待办事项应用的实现过程,它涉及到了 Vue 数据绑定、组件、路由等技术。当然,这只是一个简单的例子,你可以根据自己的需要添加更多的功能和交互效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值