Skip to content

Vue.js 项目常见问题

Vue2 如何引入组件

第一步:

js
导入组件
import AppComponent from './components/AppComponent.vue';

第二步:

js
 components: {
   MyComponent,
  },
components 对象中进行了注册。注册的组件名称是 'MyComponent',这个名称可以在模板中作为 HTML 元素使用。对应的组件选项对象是 MyComponent,这是从 MyComponent.vue 文件中导入的。

第三步:

vue
渲染组件
<template>
  <div>
    <MyComponent></MyComponent>
  </div>
</template>

Vue2 父组件向子组件传参

首先,在父组件中,你可以这样使用子组件,并传递参数:

vue
<!-- Parent.vue -->
<template>
  <div>
    <Child :message="parentMessage" /> <!-- 通过 v-bind 或 简写形式 : 将数据传递给子组件的 props -->
  </div>
</template>

<script>
import Child from './Child.vue';

export default {
  components: {
    Child
  },
  data() {
    return {
      parentMessage: 'Hello from parent', // 要传递给子组件的数据
    };
  },
};
</script>

然后,在子组件中,你需要通过 props 选项来接收这个参数:

vue
<!-- Child.vue -->
<template>
  <div>
    {{ message }} <!-- 在模板中使用从父组件接收的参数 -->
  </div>
</template>

<script>
export default {
  props: ['message'], // 声明从父组件接收的 props
};
</script>

这样,父组件就可以向子组件传递参数了。在子组件中,你可以像使用普通的数据属性一样使用这个参数。注意,props 是单向数据流,也就是说,子组件不能修改接收到的 props,否则 Vue 会在控制台中给出警告。

Vue2 子组件向父组件传参

首先,在子组件中,你可以使用 this.$emit(eventName, params) 来触发一个事件,并发送消息:

vue
<!-- Child.vue -->
<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
export default {
  data() {
    return {
      childMessage: 'Hello from child', // 要发送给父组件的消息
    };
  },
  methods: {
    sendMessage() {
      this.$emit('message', this.childMessage); // 触发名为 'message' 的事件,并发送消息
    },
  },
};
</script>

然后,在父组件中,你需要监听这个事件并处理消息:

vue
<!-- Parent.vue -->
<template>
  <div>
    <Child @message="handleMessage" /> <!-- 监听子组件的事件,并处理消息 -->
    <p>{{ receivedMessage }}</p>
  </div>
</template>

<script>
import Child from './Child.vue';

export default {
  components: {
    Child
  },
  data() {
    return {
      receivedMessage: '', // 用来存放从子组件接收的消息
    };
  },
  methods: {
    handleMessage(message) {
      this.receivedMessage = message; // 处理消息
    },
  },
};
</script>

在这个例子中,当在子组件中点击按钮时,会触发名为 'message' 的事件,并发送 childMessage。然后在父组件中,监听到这个事件后,会执行 handleMessage 方法,并将 childMessage 作为参数传入,然后将接收到的消息存储到 receivedMessage 中。

注意,在父组件中,事件名称应为原始的驼峰命名,而在模板中,需要使用 kebab-case 形式。所以 this.$emit('message') 在模板中应写为 @message。

props 属性

以下是为您注释并修改的代码:

  1. 在这个组件中,我们定义了两个prop:'visible'和'data'。'visible'是一个布尔类型的prop,默认值为false,但是它是必须的,表示这个对话框是否应该可见。'data'是一个对象类型的prop,它也是必须的,用于存储对话框中要显示的详细信息。此外,我们还定义了一些本地的data,例如表单的标签宽度和表单的详细信息。
js
export default {
  name: 'FileDialogDetail',
  props: {
    // 是否显示对话框,必需属性,默认为false
    visible: {type: Boolean, default: false, required: true},
    // 对话框中要显示的数据,必需属性,默认为空对象
    data: {type: Object, default: () => ({}), required: true}
  },
  data() {
    return {
      // 表单标签宽度
      formLabelWidth: '120px',
      // 表单详细信息,包括名称,日期,状态,进度
      formDetail: {
        name: '', // 名称
        date: '', // 日期
        status: '', // 状态
        progress: 0 // 进度
      }
    };
  },
}
  1. 在这个版本的组件中,我们使用数组的方式定义了props,它比第一种方式简单但不严谨。这种方式下我们不能定义每个prop的类型,也不能设置默认值,而且更不能强制某个prop是必需的。但如果您的项目不需要这些功能,这种方式会更简单、更快。
js
export default {
  name: 'FileDialogDetail',
  // 以数组方式定义props,元素为prop的名称
  props: ['visible', 'data'],
  data() {
    return {
      // 表单标签宽度
      formLabelWidth: '120px',
      // 表单详细信息,包括名称,日期,状态,进度
      formDetail: {
        name: '', // 名称
        date: '', // 日期
        status: '', // 状态
        progress: 0 // 进度
      }
    };
  },
}

Vue computed 计算属性

在Vue.js中,计算属性(Computed Property)是一种能够更高效,更清晰的处理数据操作的方式,特别是当你想要基于某些数据来进行复杂的逻辑运算或异步操作时。计算属性是一个函数,它的结果将被缓存,只有在它的依赖项发生改变时才会重新计算。

下面是如何定义计算属性的一个例子:

vue
<template>
  <div>
    <p>原始字符串: "{{ originalText }}"</p>
    <p>反转字符串: "{{ reversedText }}"</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      originalText: 'Hello, Vue!'
    }
  },
  computed: {
    reversedText() {
      return this.originalText.split('').reverse().join('');
    }
  }
}
</script>

在这个例子中,reversedText就是一个计算属性,它会返回originalText的反转字符串。由于计算属性的结果是被缓存的,因此,只有当originalText发生改变时,reversedText才会重新计算。

如果你在模板中频繁使用带有复杂逻辑的表达式,那么最好使用计算属性。这样可以提高代码的可读性和性能。

需要注意的是,计算属性默认只有 getter ,但也可以提供一个 setter 。

vue
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

这样,当你执行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新。

Vue watch 观察者监听数据变化

在Vue.js中,观察者 (Watchers) 是一种更通用的响应数据变化的方法。你可以通过观察者来监听某个特定的数据项,当这个数据项发生变化时,观察者就会执行一个回调函数。

在大多数情况下,你可能更倾向于使用计算属性而不是观察者。当你想要在数据变化时执行异步操作或者在数据变化时执行大量操作,观察者更为合适。

这是一个使用观察者的例子:

vue
<template>
  <div>
    <p>{{ counter }}</p>
    <button @click="increaseCounter">Increase</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter(newVal, oldVal) {
      console.log(`counter changed from ${oldVal} to ${newVal}`);
    }
  },
  methods: {
    increaseCounter() {
      this.counter++;
    }
  }
}
</script>

在这个例子中,我们创建了一个名为counter的数据项,并设置了一个观察者来监听它的变化。每当counter的值发生变化时,我们就会在控制台中打印一条消息。

在Vue.js中,watch选项确实有deepimmediate这两个非常重要的参数。

  1. deep: 默认情况下,watch仅观察到对象的“表面”级别的改变。也就是说,如果你在观察一个对象,那么在对象的属性改变时,watch是不会被触发的。但是,如果你想要深度观察一个对象,即便对象的属性改变也能触发watch,那么你需要设置deep参数为true

  2. immediate: 默认情况下,当观察的数据项第一次绑定时,watch的回调不会被执行。如果你想要在绑定时立即执行回调,你需要设置immediate参数为true

以下是这两个参数的用法:

vue
<template>
  <div>
    <p>{{ counter }}</p>
    <button @click="increaseCounter">Increase</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      counter: 0
    }
  },
  watch: {
    counter: {
      handler(newVal, oldVal) {
        console.log(`counter changed from ${oldVal} to ${newVal}`);
      },
      deep: true, // 可以观察到对象的深度改变
      immediate: true // 在绑定时立即执行
    }
  },
  methods: {
    increaseCounter() {
      this.counter++;
    }
  }
}
</script>

在这个例子中,counter的观察者被设置为一个对象,而不仅仅是一个函数。handler属性就是watch的回调函数,deepimmediate就是我们刚刚讨论的两个参数。deep在此例中没有实际意义,因为counter是一个简单类型,但是在你观察的是对象或数组的情况下,deep就非常有用了。当immediate被设置为true时,回调将在第一次绑定时被立即执行。

所以,通过这两个参数,你可以更加灵活地控制你的watch观察者。

Vue computed 和 watch 的区别, 什么时候用watch 什么时候用computed

在 Vue.js 中,计算属性(Computed)和观察者(Watchers)都是用来在响应数据变化的,但它们有一些重要的区别。

  1. 计算属性(Computed):

    • 适用于任何复杂逻辑,可以依赖多个属性。
    • 结果会被缓存,只有在依赖项变化时才会重新计算。
    • 定义为一个方法,但是访问的时候像属性一样访问,不需要加()。
    • 默认只有 getter,但是也可以有 setter。
  2. 观察者(Watch):

    • 当需要在数据变化响应时执行异步或大量操作时,使用 watch 比较合适。
    • 当数据变化时,执行一个函数。
    • 可以监听一个属性,也可以监听一个函数。

那么,何时使用哪个呢?

  • 如果你只是想要根据某个状态的变化来计算出新的状态,那么你应该使用计算属性。这是因为计算属性可以缓存计算结果,当依赖数据未发生改变时,重复访问计算属性会直接返回之前的计算结果,而不必再次执行函数,这对性能优化是很有帮助的。

  • 如果你想要执行的操作会导致一些副作用(例如 AJAX 请求),或者你需要在数据变化时执行一些额外的操作,那么你应该使用 watch。这是因为 watch 允许我们对异步操作进行响应,允许我们在数据变化时执行复杂的逻辑,或者如果你想要在数据变化时做一些事情(例如,发送 AJAX 请求或打印日志),那么 watch 更适合。

总的来说,计算属性更适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是其它计算属性计算得来的;而观察者提供了一种更通用的方式来响应数据的变化,允许我们执行异步操作、复杂逻辑或调试代码。

Vue .sync 修饰符

在 Vue.js 中,.sync 是一个用于双向数据绑定的修饰符,它是 v-bindv-on 的语法糖。

简单地说,它可以方便地让父组件和子组件之间进行双向数据通信。在 2.x 版本中,Vue 移除了 v-model 在组件上的实现,而推荐使用 .sync 来进行双向绑定。

注意,.sync 并不是真正的数据双向绑定,它其实是一个“单向数据流”的语法糖。子组件不可以直接修改父组件传递过来的 prop,而是通过触发一个事件通知父组件去修改数据。

假设你有一个自定义的组件,你想让它的某个 prop 支持 .sync,你可以这样做:

vue
<template>
  <button @click="changeValue">{{ value }}</button>
</template>

<script>
export default {
  props: ['value'],
  methods: {
    changeValue() {
      this.$emit('update:value', 'new value')
    }
  }
}
</script>

在上面的例子中,我们触发了一个 update:value 的事件,并传递了新的值 'new value'

然后在父组件中,你可以使用 .sync 来监听这个事件,并更新相应的数据:

vue
<template>
  <my-component :value.sync="myValue"></my-component>
</template>

<script>
import MyComponent from './MyComponent.vue'

export default {
  components: { MyComponent },
  data() {
    return {
      myValue: 'old value'
    }
  }
}
</script>

在上面的例子中,当 MyComponent 触发 update:value 事件时,myValue 就会被更新为 'new value'

这就是 .sync 的工作原理,它可以让你更简单地进行双向数据绑定。

Vue v-bind="$attrs" v-on="$listeners" 的作用