1- MVC 初识

32 阅读4分钟

第一节

1.请求资源

  • 异步请求:
    • 数据: 字符串、数字、JSON、XML
  • 文件(视频、音频、文本文件、HTML/JS/CSS/...)

2.请求的前提

  • 1.一定要有资源
  • 2.资源的来源 -> 服务器(本质就是台电脑)
  • 3.有地址 -> API/URI(资源定位)
    • 通过一个资源定位在服务器上找到某个特定的资源

3.响应的前提

  • 1.服务器允许请求
  • 2.确认有资源定位对应的资源
  • 3.将这个资源返回给 请求方(浏览器or服务器)

4.资源是拿来干嘛的?

  • 页面 -> html -> 服务器(所有的资源其实都是在服务器上)
    • 请求服务器响应这个资源HTML -> 将HTML响应回客户端 -> 下载这个文件的过程/加载这个文件编码的过程
    • HTML编码 -> 浏览器 -> 解析
      • link -> 下载css文件
      • body -> 解析HTML -> 组装DOM树
      • script -> 阻塞 -> 下载js文件 -> 解析JS编码 -> 执行

5.WEB项目运行环境问题

  • 服务器 -> web 文件夹 / www.xxx.com/test(域名映射到w… -> index.html(假设文件) -> 响应 -> 这样才能访问到
  • 静态文件夹 -> 允许你的访问 HTML/CSS/JS/开放的文件 -> 都有浏览器环境运行

前端/后端

  • 前端 -> 将资源从服务器上响应回来,在前端运行
  • 后端 -> 将资源拿出来直接在服务器里运行

主要在响应:响应回来的就能看到否则看不到

第二节

服务端渲染和js动态渲染

const express = require('express');
const app = express();
const { join } = require('path');

// 设置静态资源目录
app.use(express.static(join(__dirname, 'public')));

app.get('/html_test', (req, res) => {
  const title = 'This is a html text';
  const list = [
    {
      id: 1,
      name: 'Mike',
      age: 6,
      score: 6
    },
    {
      id: 2,
      name: 'Jodan',
      age: 8,
      score: 8
    },
    {
      id: 3,
      name: 'James',
      age: 10,
      score: 10
    },
  ];
  res.send(`
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <link rel="stylesheet" href="./css/static.css">
    </head>
    <body>
      <div id="app">
        <h1>${ title }</h1>
        <ul>
          ${
            list.map(item => {
              return (
                `
                  <li>
                    <p>ID:${item.id}</p>
                    <p>Name:${item.name}</p>
                    <p>Age:${item.age}</p>
                    <p>Score:${item.score}</p>
                  </li>
                `
              )
            }).join(',')
          }
        </ul>
      </div>
      <script src="./js/static.js"></script>
    </body>
    </html>
  `)
})
app.listen(8080, (req, res) => console.log("running"))

js动态渲染的格式

  • 浏览器拿到对应一个html模板
  • 通过下载js脚本,获取标签,进行元素的创建插入等,形成想要的页面构造
// 如html中的script代码如下
const oApp = document.querySelector('#app');
const oContent = document.createElement('p');
oContent.innerHTML = "哈哈哈";
oApp.appendChild(oContent);

服务端渲染和js动态渲染区别

  • 前者是后端拼接好返回的html字符串
  • 后者是返回一个html文件,再通过加载解析js内部对dom的操作进行渲染

混编模式

http://localhost:8080/index.php -> 请求 -> URL -> 服务器 -> 映射到这个资源 -> php解释器 -> php文件 -> php源码 -> 执行输出结果给HTML -> 响应回客户端

问什么js文件不能做到这个,因为浏览器默认认为js是一个脚本

ejs基础使用

const express = require('express');
const app = express();
const { join } = require('path');

// 设置ejs做为模板引擎 默认目录views
app.set('view engine', 'ejs');

// 设置静态资源目录
app.use(express.static(join(__dirname, 'public')));

app.get('/html.ejs', (req, res) => {
  res.render('html')// html -> views/html.ejs
})
app.listen(8080, (req, res) => console.log("running"))
  • views/html.ejs
<%
  const title = 'This is a ejs text';
  const list = [
    {
      id: 1,
      name: 'Mike',
      age: 6,
      score: 6
    },
    {
      id: 2,
      name: 'Jodan',
      age: 8,
      score: 8
    },
    {
      id: 3,
      name: 'James',
      age: 10,
      score: 10
    },
  ];
%>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <h1><%= title %></h1>
    <ul>
      <% list.map(item => { %>
        <li>
          <p>ID:<%= item.id %></p>
          <p>Name:<%= item.name %></p>
          <p>Age:<%= item.age %></p>
          <p>Score: <%= item.score %></p>
        </li>
      <% }) %>
    </ul>
  </div>
</body>
</html>

可以进行模板拆分以上面为例

  1. 重复的静态模板部分可以拆分出去, 引用时候 <%- include('模板文件名') %>
  2. 动态渲染的数据, 引用时候 <%- include('模板文件名', {data}) %>,把data数据传递下去
  3. 把逻辑和模板抽离出来
  • views/top.ejs(静态模板)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  • views/bottom.ejs(静态模板)
</body>
</html>
  • views/listitem.ejs(动态模板)
<li>
  <p>ID:<%= item.id %></p>
  <p>Name:<%= item.name %></p>
  <p>Age:<%= item.age %></p>
  <p>Score: <%= item.score %></p>
</li>
  • views/html.ejs
<%
  const title = 'This is a ejs text';
  const list = [
    {
      id: 1,
      name: 'Mike',
      age: 6,
      score: 6
    },
    {
      id: 2,
      name: 'Jodan',
      age: 8,
      score: 8
    },
    {
      id: 3,
      name: 'James',
      age: 10,
      score: 10
    },
  ];
%>

<%- include('top') %>
  <div id="app">
    <h1><%= title %></h1>
    <ul>
      <% list.map(item => { %>
        <%- include('listitem', {
          item
        }) %>
      <% }) %>
    </ul>
  </div>
<%- include('bottom') %>
  • app.js
const express = require('express');
const app = express();
const { join } = require('path');

// 设置ejs做为模板引擎 默认目录views
app.set('view engine', 'ejs');

// 设置静态资源目录
app.use(express.static(join(__dirname, 'public')));

app.get('/html.ejs', (req, res) => {
  const title = 'This is a ejs text';
  const list = [
    {
      id: 1,
      name: 'Mike',
      age: 6,
      score: 6
    },
    {
      id: 2,
      name: 'Jodan',
      age: 8,
      score: 8
    },
    {
      id: 3,
      name: 'James',
      age: 10,
      score: 10
    },
  ];
  res.render('html', {
    // 传递数据
    title,
    list
  })// html -> views/html.ejs
})
app.listen(8080, (req, res) => console.log("running"))

第三节

抽离MVC层

  • 让职责变得明确,该做啥的做啥

一个简单的 列表跳详情页面

  • 目录结构如下:
|- controllers (控制器)
  | - index.js
|- data(存放的数据目录,后面会用数据库代替)
  | - data.json
|- models (模块:`用来处理数据的增删改查等功能的`)
  |- index.js
|- libs 
  |- utils.js公共的方法
|- router(路由模块)
|- views (开放的静态资源)
|- app.js
  • app.js
const express = require('express');
const app = express();
const { join } = require('path');
const router = require('./router');

app.use(router);
// 设置ejs做为模板引擎 默认目录views
app.set('view engine', 'ejs');
// 设置静态资源目录
app.use(express.static(join(__dirname, 'public')));

app.listen(8080, (req, res) => console.log("running"))
  • data/data.json
{
  "titles": {
    "index": "this is homepage",
    "detail": "this is detailpage"
  },
  "list": [
    {
      "id": 1,
      "name": "Mike",
      "age": 6,
      "score": 6
    },
    {
      "id": 2,
      "name": "Jodan",
      "age": 8,
      "score": 8
    },
    {
      "id": 3,
      "name": "James",
      "age": 10,
      "score": 10
    }
  ]
}
  • libs/utils.js
// 读取文件
const { readFileSync } = require('fs');
const { resolve } = require('path');
// 读取文件数据
function readFile(path) {
  return JSON.parse(readFileSync(resolve(__dirname, path), 'utf8'));
}

module.exports = {
  readFile
}
  • router/index.js
const { Router } = require('express');
const { indexView, detailView } = require('../controllers');
const router = new Router();

// 页面之间的跳转 index.ejs
router.get('/', indexView);
// 获取详情页面 detail.ejs
router.get('/detail/:id', detailView);
module.exports = router;
  • contrillers/index.js
const { getListData, getDetailData } = require('../models');
function indexView(req, res) {
  const { title, list } = getListData();
  res.render('index', {
    title,
    list
  });
}
function detailView(req, res) {
  // params方式获取id
  const id = req.params.id;
  const { title, student } = getDetailData(id);
  res.render('detail', {
    title,
    student
  });
}

module.exports = {
  indexView,
  detailView
}
  • models/index.js
const { readFile } = require('../libs/utils');
// 处理数据的 增删改查
function getListData(req, res) {
  const data = readFile('../data/data.json');
  const title = data.titles.index;
  const list = data.list.map(({id, name}) => ({id, name}));
  return {
    title,
    list
  }
}

function getDetailData(id) {
  const data = readFile('../data/data.json');
  const title = data.titles.detail;
  const student = data.list.find(item => item.id == id);
  return {
    title,
    student
  }
}

module.exports = {
  getListData,
  getDetailData
}

views

  • views/top.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  • views/bottom.ejs
</body>
</html>
  • views/index.ejs
<%- include('top') %>
  <div>title: <%= title %></div>
  <ul>
    <% list.map(({id, name}) => { %>
      <li>
        <a href="http://localhost:8080/detail/<%= id %>"><%= name %></a>
      </li>
    <% }) %>
  </ul>
<%- include('bottom') %>
  • views/detail.ejs
<%- include('top') %>
  <div>title: <%= title %></div>
  <div>ID: <%= student.id %></div>
  <div>Name: <%= student.name %></div>
  <div>Age: <%= student.age %></div>
  <div>Score: <%= student.score %></div>
<%- include('bottom') %>

image.png

image.png