Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Key Frontend Development Concepts for Interviews

Tech May 9 4

Vue.js is a progressive JavaScript framework designed for building user interfaces. Its core library focuses on the view layer, making it easy to integrate with existing projects or to power complex single-page applications. Vue is known for its approachability, clear documentation, and solid performance, positioning it as a leading choice alongside React and Angular in the modern frontend landscape.

Essential Frontend Knowledge

Before diving deep into frameworks, a strong foundation in core web technologies is crucial:

  • HTML: Understanding semantic tags, attributes, and page structure is fundamental for accessible and well-organized content.
  • CSS: Mastery of styling rules, selectors, the box model, and layout techniques (like Flexbox and Grid) is essential for creating visually appealing and responsive interfaces.
  • JavaScript: Core concepts such as objects, arrays, expressions, functions, and closures form the backbone of dynamic web applications.

Vue.js Reactive Features

The watch Property

The watch property in Vue allows you to react to changes in data properties. It's particularly useful for asynchronous operations, complex data transformations, or when you need to perform actions based on a data change, such as form validation or fetching external data.

export default {
  data() {
    return {
      userQuery: '',
      existingUsernames: ['alice', 'bob', 'charlie'],
      validationMessage: ''
    };
  },
  watch: {
    // A basic watcher function that executes when 'userQuery' changes.
    // The handler receives the new value and the old value.
    userQuery(newQuery, oldQuery) {
      if (newQuery.length > 0 && this.existingUsernames.includes(newQuery.toLowerCase())) {
        this.validationMessage = `Username '${newQuery}' is already taken.`;
      } else {
        this.validationMessage = '';
      }
      console.log(`User query changed from '${oldQuery}' to '${newQuery}'`);
    },

    // Using the object syntax for more control, e.g., 'immediate' execution.
    // This variant is often preferred for more complex watch scenarios.
    userQuery: {
      handler(newQuery, oldQuery) {
        // Simulate an API call with a delay
        setTimeout(() => {
          if (newQuery.length > 0 && newQuery.length < 3) {
            this.validationMessage = 'Query must be at least 3 characters.';
          } else if (this.existingUsernames.includes(newQuery.toLowerCase())) {
            this.validationMessage = `Username '${newQuery}' is unavailable.`;
          } else {
            this.validationMessage = '';
          }
        }, 500);
      },
      // 'immediate: true' executes the handler immediately upon component creation.
      immediate: true,
      // 'deep: true' for watching nested properties of an object (if userQuery were an object).
      // deep: true
    }
  }
};

computed Properties vs. methods

Both computed properties and methods can encapsulate logic and return a result, but they serve different primary purposes and have distinct performance characteristics:

  • Similarities: Both can define functions that perform calculations or transformations.
  • computed Properties: Are cached based on their reactive dependencies. A computed property will only re-evaluate when one of its dependencies changes. This makes them highly efficient for values that are derived from other reactive data and are frequently accessed. They are accessed like properties (this.computedValue). Computed properties can also have get and set functions for two-way data binding.
  • methods: Are simply functions that can be called at any time. They do not cache their results and will execute every time they are called or the component re-renders. They are accessed by calling them (this.methodName()). Use methods for event handlers or when you need a function to execute without relying on reactive dependency caching.

Conditional Rendering Directives

v-if vs. v-show

Vue offers two directives for conditionally rendering elements, each with different mechanisms and use cases:

  • v-if: This directive conditionally renders elements by adding or removing them from the DOM. If the condition is false, the element and its children are completely destroyed and unmounted. This approach incurs higher toggle costs but is efficient when the condition rarely changes.
  • v-show: This directive conditionally displays elements by toggling their CSS display property (display: none;). The element remains in the DOM regardless of the condition. This approach has lower toggle costs but higher initial render costs, making it suitable for elements that are frequently toggled.

Consider v-show for frequent toggling and v-if for infrequent toggling or when complete removal from the DOM is desired.

Core JavaScript and Browser APIs

Familiarity with standard JavaScript features and browser APIs is essential for any frontend developer:

  • confirm('message'): Displays a modal dialog with a specified message, an OK button, and a Cancel button. It returns true if the user clicks OK, and false otherwise.
  • prompt('message', 'default'): Displays a modal dialog that prompts the user for input. It includes a text field for input and OK/Cancel buttons. It returns the input value as a string (or null if canceled).
  • Node.insertBefore(newNode, referenceNode): Inserts a newNode before a referenceNode as a child of the Node (parent element).
  • ParentNode.appendChild(childNode): Adds a childNode to the end of the list of children of a specified ParentNode.

Component Communication in Vue

Vue provides several patterns for inter-component communication:

  1. Parent-to-Child (Props): Parent components pass data down to child components using props. A prop is a custom attribute that you register on a component. When a value is passed to a prop, it becomes a property on the child component instance.

    <!-- ParentComponent.vue -->
    <template>
      <UserProfileCard :user-data="currentUser"></UserProfileCard>
    </template>
    
    <script>
    import UserProfileCard from './UserProfileCard.vue';
    export default {
      components: { UserProfileCard },
      data() {
        return {
          currentUser: { id: 1, name: 'Alex', email: 'alex@example.com' }
        };
      }
    };
    </script>
    
    <!-- UserProfileCard.vue -->
    <template>
      <div>
        <h3>{{ userData.name }}</h3>
        <p>Email: {{ userData.email }}</p>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        userData: {
          type: Object,
          required: true,
          default: () => ({})
        }
      }
    };
    </script>
    
  2. Child-to-Parent (Events with $emit): Child components communicate up to their parent by emitting custom events. The parent component listens for these events and can react to them.

    <!-- ChildButton.vue -->
    <template>
      <button @click="triggerAction">Perform Action</button>
    </template>
    
    <script>
    export default {
      methods: {
        triggerAction() {
          this.$emit('child-action', { status: 'completed', data: 'some result' });
        }
      }
    };
    </script>
    
    <!-- ParentComponent.vue -->
    <template>
      <ChildButton @child-action="handleChildAction"></ChildButton>
      <p>Last action status: {{ latestActionStatus }}</p>
    </template>
    
    <script>
    import ChildButton from './ChildButton.vue';
    export default {
      components: { ChildButton },
      data() {
        return { latestActionStatus: 'none' };
      },
      methods: {
        handleChildAction(payload) {
          console.log('Action received from child:', payload);
          this.latestActionStatus = payload.status;
        }
      }
    };
    </script>
    
  3. Sibling or Arbitrary Components (Event Bus / Vuex): For communication between components that don't have a direct parent-child relationship:

    • Event Bus: A simple pattern using an empty Vue instance as a central event hub. Components can emit events to the bus, and other components can listen to them.

      // eventBus.js
      import Vue from 'vue';
      export const appEventBus = new Vue();
      
      <!-- ComponentA.vue -->
      <template>
        <button @click="sendMessage">Send Data to Sibling</button>
      </template>
      
      <script>
      import { appEventBus } from './eventBus';
      export default {
        methods: {
          sendMessage() {
            appEventBus.$emit('data-from-a', 'Message from Component A');
          }
        }
      };
      </script>
      
      <!-- ComponentB.vue -->
      <template>
        <div>Received: {{ receivedMessage }}</div>
      </template>
      
      <script>
      import { appEventBus } from './eventBus';
      export default {
        data() { return { receivedMessage: 'No message yet' }; },
        created() {
          appEventBus.$on('data-from-a', (data) => {
            this.receivedMessage = data;
            console.log('Component B received:', data);
          });
        },
        beforeDestroy() {
          // Important: Remove the event listener to prevent memory leaks
          appEventBus.$off('data-from-a');
        }
      };
      </script>
      
    • Vuex: For larger applications, a dedicated state management library like Vuex is recommended. It provides a centralized store for all component states, ensuring predictable state mutations.

Content Distribution with Slots

Vue's slot mechanism allows components to compose flexible and reusable templates. A slot acts as a placeholder within a component's template, which will be filled with content provided by the parent component.

  • Default Slots: <slot></slot> is a placeholder for any content passed to the component without a specific name.
  • Named Slots: <slot name="header"></slot> allows parents to target specific slots by their name attribute using template tags with v-slot:slotName (or slot="slotName" in Vue 2).
  • Scoped Slots: Allow child components to pass data back to the parent component's slot content. This is useful for making reusable components that need to provide specific data to the slot content for rendering.

Vue Directives and Modifiers

  • v-cloak: Prevents the display of uncompiled Mustache tags ({{ }}) during page load, typically by hiding the element until Vue has finished compiling it.

    <style>
      [v-cloak] { display: none; }
    </style>
    <div v-cloak>{{ message }}</div>
    
  • v-bind: Dynamically binds one or more attributes, or a component prop, to an expression. Shorthand is :attribute="expression".

  • Event Modifiers: Vue provides modifiers for event handlers to perform common tasks without manual event object handling:

    • .stop: event.stopPropagation()
    • .prevent: event.preventDefault()
    • .capture: Adds event listener in capture mode.
    • .self: Only trigger handler if event.target is the element itself.
    • .once: Listener will only be called once.
    • .passive: Improves scrolling performance (especially on mobile).
    • .left, .right, .middle: For mouse button clicks.

Other Vue Directives

  • v-pre: Skips compilation for the element and its children, displaying raw Mustache tags or static content as is.

    <span v-pre>{{ this content will not be compiled }}</span>
    <!-- Output: {{ this content will not be compiled }} -->
    
  • v-text: Updates an element's textContent. It's similar to Mustache interpolation ({{ }}) but directly sets the text content, making it useful for preventing flicker on slow connections.

  • v-html: Updates an element's innerHTML with raw HTML content. Use with caution to prevent XSS vulnerabilities.

  • v-else: Used in conjunction with v-if to provide an "else" block.

  • v-else-if: Provides an "else if" block for v-if.

  • v-for: Renders a list of items based on an array or object.

  • v-on: Attaches event listeners. Shorthand is @event="handler".

  • v-model: Creates a two-way data binding on form input elements.

Web Storage: localStorage

localStorage provides a way for web applications to store key-value pairs locally within the browser, persistently across browser sessions. It's part of the Web Storage API.

  • localStorage.setItem(key, value): Stores a value under a specified key. Both key and value must be strings. For storing objects or arrays, use JSON.stringify() to convert them to a string first.
  • localStorage.getItem(key): Retrieves the value associated with a key. The returned value is a string, so for stored objects/arrays, use JSON.parse() to convert it back.
  • localStorage.removeItem(key): Deletes the key-value pair for the specified key.
  • localStorage.clear(): Removes all key-value pairs for the current origin.

Example:

// Store an object
const userSettings = { theme: 'dark', notifications: true };
localStorage.setItem('userPrefs', JSON.stringify(userSettings));

// Retrieve and parse the object
const retrievedSettings = JSON.parse(localStorage.getItem('userPrefs'));
console.log(retrievedSettings.theme); // 'dark'

Custom Directives in Vue

Custom directives allow developers to encapsulate reusable DOM manipulation logic. They are registered globally or locally and expose several lifecycle hooks:

  • bind: Called once, when the directive is first bound to the element. Good for one-time setup.
  • inserted: Called when the bound element has been inserted into its parent node (but not necessarily in the DOM tree).
  • update: Called when the component containing the directive is updated, but before its children are updated.
  • componentUpdated: Called after the component and its children have been updated.
  • unbind: Called once, when the directive is unbound from the element.

Example: Auto-focus Directive

// Global registration
Vue.directive('autofocus-input', {
  inserted: (element) => {
    element.focus(); // The element automatically receives focus when inserted into the DOM.
  }
});

// Usage in a component template:
// <input v-autofocus-input />
// Local registration within a component
export default {
  directives: {
    'highlight-text': {
      inserted: (el, binding) => {
        // 'binding.value' can be used to pass a value to the directive, e.g., v-highlight-text="'blue'"
        el.style.backgroundColor = binding.value || 'yellow';
      }
    }
  }
};
// Usage in a component template:
// <span v-highlight-text="'lightblue'">This text will be highlighted.</span>

Component Registration: Global vs. Local

  • Global Components: Registered using Vue.component('ComponentName', definition). Once registered, they can be used anywhere in your application without needing to be imported or registered again in individual components. Best for widely used, generic components (e.g., BaseButton, AppHeader).
  • Local Components: Imported and registered within the components option of a specific Vue component. They are only available within that component and its children. Best for specific, feature-oriented components to maintain better modularity and bundle size.

Vue Single File Components (SFCs) and Architecture

A Vue Single File Component (.vue file) encapsulates a component's template, script, and styles in a single file, facilitating modular development.

  • Structure: Comprises three main blocks:

    • <template>: Contains the component's HTML structure. Must have a single root element.
    • <script>: Houses the component's JavaScript logic (data, methods, computed properties, lifecycle hooks, etc.).
    • <style>: Cotnains the component's CSS. The scoped attribute can be used to limit styles to the current component.
  • Props Validation: Enhance component reusability and robustness by defining validation rules for props:

    • type: (e.g., String, Number, Boolean, Array, Object).
    • required: (true/false) specifies if the prop is mandatory.
    • default: Provides a default value if the prop is not passed. For Object or Array types, the default must be returned from a factory function.
  • Dynamic Components: The <component :is="componentName"> tag allows dynamic switching between components based on the componentName value.

  • keep-alive: A built-in component that can wrap dynamic components or router views to cache them, preventing re-rendering on subsequent visits. This helps maintain component state and improve performance.

  • Lifecycle Hooks: mounted is a common hook for performing DOM manipulations or fetching data immediately after the component is inserted into the DOM.

  • MVVM Pattern: Vue adheres to the Model-View-ViewModel (MVVM) architectural pattern. The Model represents the raw data, the View is the DOM, and the ViewModel (Vue instance) acts as a bridge, automatically synchronizing data between the Model and the View via reactive two-way data binding.

Frontend Build and Project Management

CSS Preprocessor Integration (e.g., Stylus)

To use CSS preprocessors like Stylus, Sass, or Less in a Vue CLI project, you typically install the preprocessor and its corresponding webpack loader.

# For Stylus
npm install stylus stylus-loader --save-dev

# Usage in a Vue component
# <style lang="stylus" scoped></style>

Common Frontend Technologies

Beyond Vue's core, a rich ecosystem of tools and libraries enhances development:

  • Routing: vue-router for single-page application navigation.
  • State Management: vuex for centralized state management in large applications.
  • UI Frameworks: Element UI, Mint UI (for mobile) provide ready-to-use component sets.
  • Performance: vue-lazyload for lazy loading images.
  • Scrolling/Swiping: vue-scroller, better-scroll, swiper for touch-friendly interfaces.
  • Date Handling: moment.js (legacy, consider alternatives like date-fns) for parsing, validating, manipulating, and formatting dates.

Typical Vue CLI Project Structure

When starting with Vue CLI, a common project structure emerges:

  • build/ & config/: Contains Webpack and build-related configurations (often less frequently modified).
    • config/index.js: Defines development server port and asset paths.
  • node_modules/: Directory for installed npm packages.
  • src/: The main source code directory.
    • main.js: The application's entry point, where Vue instance is initialized and plugins are registered.
    • App.vue: The root component of the application.
    • api/: Modules for backend API interactions.
    • assets/: Static assets like images, fonts, global styles.
    • components/: Reusable, non-route-specific UI components.
    • filters/: Custom Vue filters.
    • mock/: Mock data or API endpoints for development.
    • pages/ or views/: Route-specific components that represent full pages.
    • router/: Vue Router configuration.
    • store/: Vuex store modules.
  • public/ or static/: Directly served static assets.
  • .babelrc: Babel configuration for JavaScript transpilation.
  • .eslintrc.js: ESLint configuration for code linting.
  • index.html: The main HTML file where the Vue app is mounted.
  • package.json: Project metadata, dependencies, and scripts.

Mobile Web Development Considerations

  1. Viewport Configuration: Ensuring proper scaling and responsiveness on various devices.

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
    
  2. 300ms Click Delay: Older mobile browsers introduce a 300ms delay between touchend and click events. Libraries like FastClick can mitigate this for a snappier user experience.

    <script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script>
    <script>
      if ('addEventListener' in document) {
        document.addEventListener('DOMContentLoaded', function() {
          FastClick.attach(document.body);
        }, false);
      }
    </script>
    

Advanced JavaScript Concepts

Arrow Functions and this Binding

Arrow functions (=>) provide a concise syntax for writing fucntions. Their key characteristic is lexical this binding: they do not have their own this context. Instead, this inside an arrow function refers to the this value of the enclosing lexical scope (where the arrow function is defined), rather than where it's called. In contrast, regular functions (function) have a dynamic this that depends on how they are called.

Closures

A closure is a function that remembers its lexical environment even when it's executed outside that lexical scope. This means a closure can access variables from its parent function's scope even after the parent function has finished executing.

function createItemCounter(initialCount) {
  let currentCount = initialCount; // 'currentCount' is the variable captured by the closure
  return function increment() {
    currentCount++;
    return currentCount;
  };
}

const widgetCounter = createItemCounter(0);
console.log(widgetCounter()); // 1
console.log(widgetCounter()); // 2

const anotherCounter = createItemCounter(10);
console.log(anotherCounter()); // 11

JavaScript Pre-compilation (Parsing)

Before JavaScript code is executed, it undergoes a phase often referred to as

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.