沃梦达 / IT编程 / 前端开发 / 正文

用原生js做单页应用

下面我将为大家详细讲解如何用原生JS做单页应用的完整攻略。

下面我将为大家详细讲解如何用原生JS做单页应用的完整攻略。

什么是单页应用?

单页应用(SPA)是指使用Ajax或Websocket等技术,使得网页只需加载一次,就能实现多个页面的效果。

用原生JS做单页应用的步骤

  1. 定义路由
    要实现单页应用,首先需要定义路由,以此来控制页面的跳转和展示。可以使用window.history.pushState()方法或者location.hash来实现路由。

示例代码:

// 定义路由表
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact }
]

// 监听路由变化
window.addEventListener('popstate', routeChanged);

// 路由跳转
function navigateTo(path) {
  history.pushState(null, null, path);
  routeChanged();
}

// 路由变化处理函数
function routeChanged() {
  const path = location.pathname;
  const route = routes.find(route => route.path === path) || {component: NotFound};
  document.querySelector('#content').innerHTML = new route.component().render();
}
  1. 定义组件
    为了实现复用和组合,需要将页面拆分成多个组件。每个组件可以由一个HTML模板和一个JS逻辑文件组成。

示例代码:

// Home组件
class Home {
  constructor() {
    this.template = `
      <h1>Welcome to Home Page</h1>
      <p>Home Page Content Here</p>
    `;
  }

  render() {
    return this.template;
  }
}

// About组件
class About {
  constructor() {
    this.template = `
      <h1>About Us</h1>
      <p>About Us Content Here</p>
    `;
  }

  render() {
    return this.template;
  }
}

// Contact组件
class Contact {
  constructor() {
    this.template = `
      <h1>Contact Us</h1>
      <p>Contact Us Content Here</p>
    `;
  }

  render() {
    return this.template;
  }
}

// NotFound组件
class NotFound {
  constructor() {
    this.template = `
      <h1>Not Found</h1>
      <p>404 Page Not Found</p>
    `;
  }

  render() {
    return this.template;
  }
}
  1. 编写事件处理函数和业务逻辑
    单页应用中,事件处理函数和业务逻辑通常写在组件中。可以使用事件委托和事件监听等方法来实现交互效果。

示例代码:

// 定义事件处理函数
function handleClick(event) {
  event.preventDefault();
  const path = event.target.href;
  navigateTo(path);
}

// 组件中使用事件处理函数
class Navigation {
  constructor() {
    this.template = `
      <nav>
        <ul>
          <li><a href="/" class="link">Home</a></li>
          <li><a href="/about" class="link">About</a></li>
          <li><a href="/contact" class="link">Contact</a></li>
        </ul>
      </nav>
    `;
  }

  render() {
    const element = document.createElement('div');
    element.innerHTML = this.template.trim();
    element.addEventListener('click', handleClick); // 事件委托
    return element;
  }
}

// 业务逻辑处理函数
function handleSubmit(event) {
  event.preventDefault();
  const formData = new FormData(event.target);
  const data = Object.fromEntries(formData.entries());
  // 处理提交数据...
}

// 组件中使用业务逻辑处理函数
class Form {
  constructor() {
    this.template = `
      <form>
        <label>
          Name: <input type="text" name="name" required>
        </label>
        <label>
          Email: <input type="email" name="email" required>
        </label>
        <button type="submit">Submit</button>
      </form>
    `;
  }

  render() {
    const element = document.createElement('div');
    element.innerHTML = this.template.trim();
    element.querySelector('form').addEventListener('submit', handleSubmit);
    return element;
  }
}

示例说明

示例一:基础单页应用

下面是一个基础的单页应用示例,实现了路由跳转和组件渲染。

<html>
<head>
  <title>Example SPA</title>
</head>
<body>
  <nav>
    <ul>
      <li><a href="/" class="link">Home</a></li>
      <li><a href="/about" class="link">About</a></li>
      <li><a href="/contact" class="link">Contact</a></li>
    </ul>
  </nav>
  <div id="content"></div>
  <script>
    // 定义路由表
    const routes = [
      { path: '/', component: Home },
      { path: '/about', component: About },
      { path: '/contact', component: Contact }
    ];

    // 监听路由变化
    window.addEventListener('popstate', routeChanged);

    // 路由跳转
    function navigateTo(path) {
      history.pushState(null, null, path);
      routeChanged();
    }

    // 路由变化处理函数
    function routeChanged() {
      const path = location.pathname;
      const route = routes.find(route => route.path === path) || {component: NotFound};
      document.querySelector('#content').innerHTML = new route.component().render();
    }

    // Home组件
    class Home {
      constructor() {
        this.template = `
          <h1>Welcome to Home Page</h1>
          <p>Home Page Content Here</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // About组件
    class About {
      constructor() {
        this.template = `
          <h1>About Us</h1>
          <p>About Us Content Here</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // Contact组件
    class Contact {
      constructor() {
        this.template = `
          <h1>Contact Us</h1>
          <p>Contact Us Content Here</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // NotFound组件
    class NotFound {
      constructor() {
        this.template = `
          <h1>Not Found</h1>
          <p>404 Page Not Found</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // 定义事件处理函数
    function handleClick(event) {
      event.preventDefault();
      const path = event.target.href;
      navigateTo(path);
    }

    // Navigation组件
    class Navigation {
      constructor() {
        this.template = `
          <nav>
            <ul>
              <li><a href="/" class="link">Home</a></li>
              <li><a href="/about" class="link">About</a></li>
              <li><a href="/contact" class="link">Contact</a></li>
            </ul>
          </nav>
        `;
      }

      render() {
        const element = document.createElement('div');
        element.innerHTML = this.template.trim();
        element.addEventListener('click', handleClick); // 事件委托
        return element;
      }
    }

    document.querySelector('#content').appendChild(new Navigation().render());
    routeChanged();
  </script>
</body>
</html>

示例二:表单提交处理

下面是一个实现表单提交处理的单页应用示例,演示了如何在组件中处理交互事件和业务逻辑。

<html>
<head>
  <title>Example SPA</title>
</head>
<body>
  <nav>
    <ul>
      <li><a href="/" class="link">Home</a></li>
      <li><a href="/about" class="link">About</a></li>
      <li><a href="/contact" class="link">Contact</a></li>
    </ul>
  </nav>
  <div id="content"></div>
  <script>
    // 定义路由表
    const routes = [
      { path: '/', component: Home },
      { path: '/about', component: About },
      { path: '/contact', component: Contact }
    ];

    // 监听路由变化
    window.addEventListener('popstate', routeChanged);

    // 路由跳转
    function navigateTo(path) {
      history.pushState(null, null, path);
      routeChanged();
    }

    // 路由变化处理函数
    function routeChanged() {
      const path = location.pathname;
      const route = routes.find(route => route.path === path) || {component: NotFound};
      document.querySelector('#content').innerHTML = new route.component().render();
    }

    // Home组件
    class Home {
      constructor() {
        this.template = `
          <h1>Welcome to Home Page</h1>
          <p>Home Page Content Here</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // About组件
    class About {
      constructor() {
        this.template = `
          <h1>About Us</h1>
          <p>About Us Content Here</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // Contact组件
    class Contact {
      constructor() {
        this.template = `
          <h1>Contact Us</h1>
          <p>Contact Us Content Here</p>
          <h2>Feedback Form</h2>
          <div id="form"></div>
        `;
      }

      render() {
        const element = document.createElement('div');
        element.innerHTML = this.template.trim();
        element.querySelector('#form').appendChild(new ContactForm().render());
        return element;
      }
    }

    // NotFound组件
    class NotFound {
      constructor() {
        this.template = `
          <h1>Not Found</h1>
          <p>404 Page Not Found</p>
        `;
      }

      render() {
        return this.template;
      }
    }

    // ContactForm组件
    class ContactForm {
      constructor() {
        this.template = `
          <form>
            <label>
              Name: <input type="text" name="name" required>
            </label>
            <label>
              Email: <input type="email" name="email" required>
            </label>
            <label>
              Message: <textarea name="message" rows="5" required></textarea>
            </label>
            <button type="submit">Submit</button>
          </form>
        `;
      }

      render() {
        const element = document.createElement('div');
        element.innerHTML = this.template.trim();
        element.querySelector('form').addEventListener('submit', handleSubmit);
        return element;
      }
    }

    // 提交处理函数
    function handleSubmit(event) {
      event.preventDefault();
      const formData = new FormData(event.target);
      const data = Object.fromEntries(formData.entries());
      console.log(data);
      // 处理提交数据...
      event.target.reset();
      alert('Submit success.');
    }

    // 定义事件处理函数
    function handleClick(event) {
      event.preventDefault();
      const path = event.target.href;
      navigateTo(path);
    }

    // Navigation组件
    class Navigation {
      constructor() {
        this.template = `
          <nav>
            <ul>
              <li><a href="/" class="link">Home</a></li>
              <li><a href="/about" class="link">About</a></li>
              <li><a href="/contact" class="link">Contact</a></li>
            </ul>
          </nav>
        `;
      }

      render() {
        const element = document.createElement('div');
        element.innerHTML = this.template.trim();
        element.addEventListener('click', handleClick); // 事件委托
        return element;
      }
    }

    document.querySelector('#content').appendChild(new Navigation().render());
    routeChanged();
  </script>
</body>
</html>

以上就是用原生JS做单页应用的详细攻略,希望对大家有所帮助。

本文标题为:用原生js做单页应用