Fork me on GitHub

过滤器、按键修饰符、指令、生命周期

# Vue 第二天

以做案例逐渐深入学习

打好基础很重要!

believe in yourself

# 品牌列表案例

<div id="app">
  <div class="panel panel-primary">
    <div class="panel-heading">
      <div class="panel-title">添加品牌</div>
    </div>
    <div class="panel-body form-inline">
      <label for="id">id: </label>
      <input type="text" class="form-control" v-model="id" id="id" />
      <label for="name">name: </label>
      <input type="text" class="form-control" v-model="name" id="name" />
      <button class="btn  btn-primary" @click="add">添加</button>
    </div>
  </div>
  <table class="table table-bordered table-hover table-striped">
    <thead>
      <tr>
        <th>id</th>
        <th>name</th>
        <th>ctime</th>
        <th>Operation</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="item in list" :key="item.id">
        <td>{{item.id}}</td>
        <td>{{item.name}}</td>
        <td>{{item.ctime}}</td>
        <td><a href="" @click.prevent="del(item.id)">删除</a></td>
      </tr>
    </tbody>
  </table>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      id: "",
      name: "",
      list: [
        {
          id: 1,
          name: "奔驰",
          ctime: new Date(),
        },
        {
          id: 2,
          name: "宝马",
          ctime: new Date(),
        },
      ],
    },
    methods: {
      add() {
        let car = { id: this.id, name: this.name, ctime: new Date() };
        this.list.push(car);
        this.name = this.id = "";
      },
      del(id) {
        let index = this.list.findIndex((item) => {
          if (item.id == id) {
            return true;
          }
        });
        this.list.splice(index, 1);
      },
    },
  });
</script>

mark

mark

mark

mark

# 增加搜索功能

# 方法一

<tr v-for="item in search(keywords)" :key="item.id">
  <td>{{item.id}}</td>
  <td>{{item.name}}</td>
  <td>{{item.ctime}}</td>
  <td><a href="" @click.prevent="del(item.id)">删除</a></td>
</tr>
<script>
  methods: {
      search(keywords){//根据关键字进行数据的搜索
          let newList=[]
          this.list.forEach((item)=>{
              if(item.name.indexOf(keywords)!= -1){
                  newList.push(item)
              }
          })
          return newList
      }
  }
</script>

# 方法二 (使用 filter)

<script>
  methods: {
      search(keywords){//根据关键字进行数据的搜索
          let newList = []
              //注意 :foreach some filter findIndex 这些都属于数组的新方法
              //都会对数组中的每一项,进行遍历,执行相关的操作
              //注意:Es6中,为字符串提供了一个新方法 ,叫做String.prototype.includes('要包含的字符串,如果包含返回true')
          newList = this.list.filter((item) => {
              // if(item.name.indexOf(keywords)!= -1)
              if (item.name.includes(keywords)) {
                  return item
              }
          })
          return newList
      }
  }
</script>

mark

mark

# 过滤器

# 全局过滤器

过滤器的定义语法Vue.filter (‘过滤器的名称’,function (){})

//过滤器中的function,第一个参数,已经被规定死了,永远都是 过滤器 管道符前面 传递过来的数据
Vue.filter("过滤器的名称", function (data) {
  return data + "123";
});

写一个例子

<div id="app">{{ msg | msgFormat}}</div>
<script>
  //定义一个Vue 全局的过滤器 名字叫做 msgFormat
  Vue.filter("msgFormat", function (msg) {
    //字符串 replace方法,第一个参数,除了可以写一个 字符串之外,还可以定义一个正则表达式
    // return msg.replace('拼尽全力','开心快乐')
    return msg.replace(/拼尽全力/g, "开心快乐");
  });
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "人活着就要拼尽全力!拼尽全力,拼尽全力,拼尽全力!",
    },
  });
</script>

mark

# 使用过滤器时(传参数)

<div id="app">{{ msg | msgFormat('开心快乐')}}</div>
<script>
  //定义一个Vue 全局的过滤器 名字叫做 msgFormat
  Vue.filter("msgFormat", function (msg, arg) {
    //字符串 replace方法,第一个参数,除了可以写一个 字符串之外,还可以定义一个正则
    // return msg.replace('拼尽全力','开心快乐')
    return msg.replace(/拼尽全力/g, arg);
  });
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "人活着就要拼尽全力!拼尽全力,拼尽全力,拼尽全力!",
    },
  });
</script>

# 使用过滤器时(传多个参数)

<div id="app">{{ msg | msgFormat('开心快乐','123')}}</div>
<script>
  //定义一个Vue 全局的过滤器 名字叫做 msgFormat
  Vue.filter("msgFormat", function (msg, arg, arg2) {
    //字符串 replace方法,第一个参数,除了可以写一个 字符串之外,还可以定义一个正则
    // return msg.replace('拼尽全力','开心快乐')
    return msg.replace(/拼尽全力/g, arg + arg2);
  });
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "人活着就要拼尽全力!拼尽全力,拼尽全力,拼尽全力!",
    },
  });
</script>

mark

# 使用过滤器时(多次调用)

<div id="app">{{ msg | msgFormat('开心快乐','123') | test}}</div>
<script>
  //定义一个Vue 全局的过滤器 名字叫做 msgFormat
  Vue.filter("msgFormat", function (msg, arg, arg2) {
    //字符串 replace方法,第一个参数,除了可以写一个 字符串之外,还可以定义一个正则
    // return msg.replace('拼尽全力','开心快乐')
    return msg.replace(/拼尽全力/g, arg + arg2);
  });

  Vue.filter("test", function (msg) {
    return msg + "test";
  });

  let vm = new Vue({
    el: "#app",
    data: {
      msg: "人活着就要拼尽全力!拼尽全力,拼尽全力,拼尽全力!",
    },
  });
</script>

mark

# 修改品牌列表案例,进行时间的格式化

# 关键代码:

<td>{{item.ctime | dataFormat}}</td>
<script>
  //全局的过滤器,进行时间的格式化
  Vue.filter("dataFormat", function (data) {
    //根据给定的时间字符串,得到特定的时间
    let dt = new Date(data);
    let y = dt.getFullYear();
    let m = dt.getMonth() + 1;
    let d = dt.getDate();
    // return y + '-' + m + '-' + d
    return `${y}-${m}-${d}`;
  });
</script>

mark

# 功能改进

<td>{{item.ctime | dataFormat('')}}</td>
<script>
  //全局的过滤器,进行时间的格式化
  Vue.filter("dataFormat", function (data, pattern) {
    //根据给定的时间字符串,得到特定的时间
    let dt = new Date(data);
    let y = dt.getFullYear();
    let m = dt.getMonth() + 1;
    let d = dt.getDate();
    // return y + '-' + m + '-' + d
    if (pattern && pattern.toLowerCase() === "yyyy-mm-dd") {
      return `${y}-${m}-${d}`;
    } else {
      let hh = dt.getHours();
      let mm = dt.getMinutes();
      let ss = dt.getSeconds();
      return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
    }
  });
</script>

mark

# 局部过滤器

过滤器调用的时候,采用的是就近原则如果私有过滤器和全局过滤器名称一致了,这时候优先调用私有过滤器

<div id="app1">{{msg | dataFormat}}</div>
<div id="app2">{{msg}}</div>
<script>
  let vm1 = new Vue({
    el: "#app1",
    data: {
      msg: new Date(),
    },
    methods: {},
    filters: {
      dataFormat: function (data, pattern) {
        let dt = new Date(data);
        let y = dt.getFullYear();
        let m = dt.getMonth() + 1;
        let d = dt.getDate();
        if (pattern && pattern.toLowerCase() === "yyyy-mm-dd") {
          return `${y}-${m}-${d}`;
        } else {
          let hh = dt.getHours();
          let mm = dt.getMinutes();
          let ss = dt.getSeconds();
          return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
        }
      },
    },
  });
  let vm2 = new Vue({
    el: "#app2",
    data: {
      msg: new Date(),
    },
  });
</script>

mark

# 时间补 0 的情况(如:2019-03-29 21:48:20)

# padStart () 的运用

let m = (dt.getMonth() + 1).toString().padStart(2, "0");
let d = dt.getDate().toString().padStart(2, "0");

# 按键修饰符

# 按回车键添加数据(不用按添加按钮)

<input
  type="text"
  class="form-control"
  v-model="name"
  id="name"
  @keyup.enter="add"
/>
<button class="btn  btn-primary" @click="add">添加</button>

# 自定义全局按键修饰符

<input
  type="text"
  class="form-control"
  v-model="name"
  id="name"
  @keyup.f2="add"
/>
<script>
  //自定义全局按键修饰符
  Vue.config.keyCodes.f2 = 113;
</script>

mark

# 自定义全局(私有)的指令

# 自定义全局指令

# 自定义一个自动获取焦点的指令(v-focus)

//参数一:指令的名称,在定义的时候,指令的名称前面,不需要加 v- 前缀,
//在调用的时候,必须 在指令名称前 加上 v- 前缀来调用
//参数二:是一个对象,在这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段执行相关的操作
Vue.directive("focus", {
  bind: function (el) {
    //每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
    //注意:在每个函数中,第一个参数永远是el,表示被绑定了指令的那个元素,这个el 参数,是一个元素的JS对象
    //在元素 刚绑定指令的时候,还没有插入到 DOM 中去,这时候,调用 focus 方法没有作用
    //因为,一个元素,只有插入 DOM 之后,才能获取焦点
    // el.focus()
  },
  inserted: function (el) {
    //inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数                                  【触发一次】
    el.focus();
    //和JS行为有关的操作,最好在 inserted 中去执行,防止 JS 行为不生效
  },
  updated: function () {
    //当vNode更新的时候,会执行 updated,可能会触发多次
  },
});

一个指令定义对象可以提供如下几个钩子函数 (均为可选):参考文档

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

  • 指令钩子函数会被传入以下参数:

    • el:指令所绑定的元素,可以用来直接操作 DOM 。
    • binding:一个对象,包含以下属性:
      name:指令名,不包括 v- 前缀。
      value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
      oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
      expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
      arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
      modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 {foo: true, bar: true}。
      vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
      oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

mark

# 自定义一个 设置字体颜色的 指令(v-color)

//样式,只要通过指令绑定了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
//将来元素肯定会显示到页面中去,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind: function (el) {
    el.style.color = 'red'
    //和样式相关的操作,一般都可以在 bind 执行
  }
})

# 自定义一个 设置字体颜色的 指令 (传参数)

<input
  class="form-control"
  id="search"
  type="text"
  v-model="keywords"
  v-color="'blue'"
  v-focus
/>
<script>
  Vue.directive("color", {
    bind: function (el, binding) {
      el.style.color = binding.value;
      //对比 value 和 expression
      console.log(binding.value);
      console.log(binding.expression);
    },
  });
</script>

mark

# 自定义私有指令

let vm1 = new Vue({
  el: "#app1",
  data: {},
  methods: {},
  directives: {
    //自定义私有指令
    fontweight: {
      bind: function (el, binding) {
        el.style.fontWeight = binding.value;
      },
    },
  },
});

# 函数简写

大多数情况下,我们可能想在 bindupdate 钩子上做重复动作,并且不想关心其它的钩子函数。可以这样写:

Vue.directive("color-swatch", function (el, binding) {
  el.style.backgroundColor = binding.value;
});

例如:自定义一个字体大小的指令

directives: { //自定义私有指令
        'fontsize': function (el, binding) { //这个 function 等同于 把代码写到 bind 和 	update 中去
            el.style.fontSize = parseInt(binding.value)+ 'px'
        }
}

# Vue 实例的生命周期

  1. 生命周期钩子 = 生命周期函数 = 生命周期事件
  2. 举例说明:
<div id="app">
  <button @click="msg='no'">修改msg</button>
  <h3 id="h3">{{msg}}</h3>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "ok",
    },
    methods: {
      show() {
        console.log("执行了show方法");
      },
    },
    beforeCreate() {
      //这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它
      // console.log(this.msg) //undefined
      // this.show()           //TypeError: this.show is not a function
      // 注意:在beforeCreate 生命周期函数执行的时候,data和methods 中的数据未被初始化
    },
    created() {
      //这是我们遇到的第二个生命周期函数
      // console.log(this.msg) //ok
      // this.show()  //执行了show方法
      //在 created中,data 和 methods 都已经被初始化好了!
      //如果要调用 methods 中的方法,或者操作 data中的数据,最早,只能在 created 中操作
    },
    beforeMount() {
      //这是我们遇到的第三个生命周期函数,表示模板已经在内存中编辑完成了,但是尚未把 模板渲染到 页面中
      console.log(document.getElementById("h3").innerText); // {{msg}}
      //在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串
    },
    mounted() {
      //这是我们遇到的第四个生命周期函数,表示内存中的模板,已经真实的挂载到页面中去,用户可以看到渲染好的页面
      console.log(document.getElementById("h3").innerText); // ok
      //注意:mounted 是 实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,
      // 此时,如果没有其它操作,这个实例,就静静的 躺在内存中,一动不动。
    },

    //接下来是运行中的两个事件
    beforeUpdate() {
      //这时候表示,我们的界面还没有被更新 【数据被更新了吗?数据肯定被更新了】
      // console.log(document.getElementById('h3').innerText) //没有输出任何东西
      console.log(
        "界面上元素的内容:" + document.getElementById("h3").innerText
      ); //界面上元素的内容:ok
      console.log("data中 msg 数据是:" + this.msg); //data中 msg 数据是:no
      //得出结论:当执行 beforeUpdate 的时候,页面中显示的数据还是旧的,此时 data 数据是最新的,页面尚未和最新的数据 保持同步
    },
    updated() {
      console.log(
        "界面上元素的内容:" + document.getElementById("h3").innerText
      ); //界面上元素的内容:no
      console.log("data中 msg 数据是:" + this.msg); //data中 msg 数据是:no
      // updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的
    },
  });
</script>

mark

# Vue-resource 实现 get,post,jsonp 请求

Vue-resource 和 axios 的区别

Vue-resource 的基本使用

<script src="../../vue.min.js"></script>
<script src="../../vue-resource-1.3.4.js"></script>
<div id="app">
  <button @click="getInfo">get请求</button>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "这是一句话!",
    },
    methods: {
      getInfo() {
        this.$http.get("../../data.json").then(function (result) {
          console.log(result);
        });
      },
    },
  });
</script>

mark

  • get,post,jsonp 请求
<div id="app">
  <button @click="getInfo">get请求</button>
  <button @click="postInfo">post请求</button>
  <button @click="jsonpInfo">jsonp请求</button>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "这是一句话!",
    },
    methods: {
      getInfo() {
        //发起 get 请求
        this.$http.get("../../data.json").then(function (result) {
          //通过 result.body 拿到服务器返回的成功的数据
          console.log(result.body);
        });
      },
      postInfo() {
        //发起 post  请求
        this.$http.post("../../data.json", {}, {}).then(function (result) {
          //通过 result.body 拿到服务器返回的成功的数据
          console.log(result.body);
        });
      },
      jsonpInfo() {
        //发起 jsonp 请求
        this.$http.jsonp("../../data.json").then(function (result) {
          //通过 result.body 拿到服务器返回的成功的数据
          console.log(result.body);
        });
      },
    },
  });
</script>

创建实例、基础指令、跑马灯、修饰符、样式、key, v-model

# Vue 第一天

这是我第 5 遍学习 Vue 了(可能是因为感觉自己达不到游刃有余的感觉吧,也可能是以前学的不系统,要学就得学扎实了。)

# 创建一个实例

<script src="../../vue.min.js"></script>
<div id="app">
  <p>{{ title }}</p>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      title: "欢迎学习Vue!",
    },
  });
</script>

# 指令

# v-cloak ( 能够解决 插值表达式闪烁问题 )

<style>
  [v-cloak] {
    display: none;
  }
</style>
<div id="app">
  <p v-cloak>{{ title }}</p>
</div>

# v-text (功能与插值表达式相同,优点:没有闪烁问题 ,缺点:会覆盖元素中原本的内容)

<p v-text="“title”"></p>

# v-html (能够解析文本里面的 HTML 标签)

<p v-html="msg"></p>

# v-bind( 用于绑定属性的指令 )(简写形式 :)

<input type="button" value="按钮" v-bind:title="mytitle" />
<input type="button" value="按钮" :title="mytitle" />

# v-on (绑定事件) (简写形式 @ )

<input type="button" value="按钮" v-on:click="alert('hello')" />
<input type="button" value="按钮" @click="alert('hello')" />

# 练习

# 跑马灯

<div id="app">
  <p>{{msg}}</p>
  <input type="button" value="开始" @click="start" />
  <input type="button" value="停止" @click="stop" />
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      msg: "猥琐发育,别浪~~~~",
      timer: null,
    },
    methods: {
      start() {
        if (this.timer != null) return;
        this.timer = setInterval(() => {
          let start = this.msg.substring(0, 1);
          let end = this.msg.substring(1);
          this.msg = end + start;
        }, 200);
      },
      stop() {
        clearInterval(this.timer);
        this.timer = null;
      },
    },
  });
</script>

mark

# 事件修饰符

# stop (阻止冒泡)

<div id="app">
  <div class="inner" @click="DivClick">
    <input type="button" value="点击" @click.stop="BtnClick" />
  </div>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {},
    methods: {
      DivClick() {
        console.log("触发了inner点击事件");
      },
      BtnClick() {
        console.log("触发了按钮点击事件");
      },
    },
  });
</script>

mark

# prevent (阻止默认行为)

<a href="http://www.baidu.com" @click.prevent="linkClick">去百度</a>

mark

# capture (捕获触发事件机制)(从外向里 )

<div class="inner" @click.capture="DivClick">
  <input type="button" value="点击" @click="BtnClick" />
</div>

mark

# self (只有点击当前元素才能触发事件)

<div class="inner" @click.self="DivClick">
  <input type="button" value="点击" @click="BtnClick" />
</div>

mark

# once (只触发一次事件)

<a href="http://www.baidu.com" @click.prevent.once="linkClick">去百度</a>

# v-model

# 案例(计算器)

# 代码:
<div id="app">
  <input type="text" v-model="n1" />
  <select name="" id="" v-model="opt">
    <option value="+">+</option>
    <option value="-">-</option>
    <option value="*">*</option>
    <option value="/">/</option>
  </select>
  <input type="text" v-model="n2" />
  <input type="button" value="=" @click="btnClick" />
  <input type="text" v-model="result" />
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      n1: 0,
      n2: 0,
      result: 0,
      opt: "+",
    },
    methods: {
      btnClick() {
        switch (this.opt) {
          case "+":
            this.result = parseInt(this.n1) + parseInt(this.n2);
            break;
          case "-":
            this.result = parseInt(this.n1) - parseInt(this.n2);
            break;
          case "*":
            this.result = parseInt(this.n1) * parseInt(this.n2);
            break;
          case "/":
            this.result = parseInt(this.n1) / parseInt(this.n2);
            break;
        }
      },
    },
  });
</script>

# 代码优化(投机取巧,正式开发中尽量少用)

(使用 eval,eval () 函数可计算某个字符串,并执行其中的的 JavaScript 代码)

<script>
  let vm = new Vue({
    el: "#app",
    data: {
      n1: 0,
      n2: 0,
      result: 0,
      opt: "+",
    },
    methods: {
      btnClick() {
        // switch (this.opt) {
        //     case '+':
        //         this.result = parseInt(this.n1) + parseInt(this.n2)
        //         break
        //     case '-':
        //         this.result = parseInt(this.n1) - parseInt(this.n2)
        //         break
        //     case '*':
        //         this.result = parseInt(this.n1) * parseInt(this.n2)
        //         break
        //     case '/':
        //         this.result = parseInt(this.n1) / parseInt(this.n2)
        //         break
        // }
        let codeStr = "parseInt(this.n1)" + this.opt + "parseInt(this.n2)";
        this.result = eval(codeStr);
      },
    },
  });
</script>

mark

mark

# Vue 中使用样式

# 使用 class 样式

# 第一种方式:直接传递一个数组

<style>
  .red {
    color: red;
  }

  .thin {
    font-weight: 200;
  }

  .italic {
    font-style: italic;
  }
</style>
<div id="app">
  <h1 :class="['red','thin','italic']">这是h1</h1>
</div>

# 在数组中使用三元表达式

<div id="app">
  <h1 :class="['red','thin',flag?'italic':'']">这是h1</h1>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      flag: true,
    },
  });
</script>

或者:

<div id="app">
  <h1 :class="['red','thin',{'italic':flag}]">这是h1</h1>
</div>
  1. 直接使用对象(true 和 false 可用变量来代替)
<div id="app">
  <h1 :class="{red:true,thin:true,italic:false}">这是h1</h1>
</div>
  1. data 里面定义
<div id="app">
  <h1 :class="classObj">这是h1</h1>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      classObj: { red: true, thin: true, italic: true },
    },
  });
</script>

# 使用内联样式

直接使用

<h1 :style="{color:'red','font-weight':200}">这是h1</h1>

data 里面调用

<div id="app">
  <h1 :style="styleObj">这是h1</h1>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      styleObj: { color: "red", "font-weight": 200 },
    },
  });
</script>

运用数组

<div id="app">
  <h1 :style="[styleObj1,styleObj2]">这是h1</h1>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      styleObj1: { color: "red", "font-weight": 200 },
      styleObj2: { "font-style": "italic" },
    },
  });
</script>

# Vue 指令之 V-for 和 key 属性

# v-for 简单实用

<div id="app">
  <ul>
    <li v-for="item in list">{{item}}</li>
  </ul>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      list: [1, 2, 3, 4, 5, 6],
    },
  });
</script>

mark

# 索引值:

<div id="app">
  <ul>
    <li v-for="(item,index) in list">{{item}}---{{index}}</li>
  </ul>
</div>

mark

# 循环对象数组

<div id="app">
  <ul>
    <li v-for="(item,index) in list">
      {{item.id}}---{{item.name}}---{{index}}
    </li>
  </ul>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      list: [
        {
          id: 1,
          name: "张三",
        },
        {
          id: 2,
          name: "李四",
        },
        {
          id: 3,
          name: "王五",
        },
        {
          id: 4,
          name: "隔壁老王",
        },
      ],
    },
  });
</script>

mark

# 遍历对象

<div id="app">
  <ul>
    <li v-for="(val,key,index) in user">{{key}}--{{val}}---{{index}}</li>
  </ul>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      user: {
        id: 1,
        name: "张三",
        hobby: "打篮球",
        sex: "男",
      },
    },
  });
</script>

mark

# 迭代数字

<div id="app">
  <p v-for="count in 5">这是第 {{count}} 次循环</p>
</div>

mark

# Vue 指令之 v-if 和 v-show

基本使用

<div id="app">
  <h3 v-if="flag">这是v-if控制的元素</h3>
  <h3 v-show="flag">这是v-show控制的元素</h3>
  <button @click="flag=!flag">点击</button>
</div>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      flag: true,
    },
  });
</script>

mark

mark

# 总结

  1. MVC 和 MVVM 的区别

  2. 学习了 Vue 中最基本的代码结构

  3. 基本指令

  4. 事件修饰符

  5. v-for 要会使用 key 属性

  6. v-model 只能应用于表单元素

适配技巧和组件化思想

# 你一定要会的适配技巧和组件化思想

rem:利用它能实现强大的屏幕适配布局

less:Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。(代表的有 less,Sass,stylus)

模板引擎:art-template(实现组件化,代码不复用,提高开发效率)(当然还有很多其它好用的模板引擎,但原理上基本一样。)

# 说明

  • 本文将介绍以 rem(结合流式布局)+less(为代表)的适配方式
  • 模板引擎上以将以 art-template 举例说明。(模板引擎 ==> 这里特指用于 Web 开发的模板引擎,是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的 HTML 文档。)

# 需求分析

为什么 rem+less 会产生?

  • remrem 是相对长度单位,相对于根元素 font-size 计算值的倍数(通俗来讲,相对于 html 字体大小)

    这种需求主要产生在移动端,因为随着科学水平的发展,手机产业发展非常迅速,作为一个前端工作者,大量的手机页面需要我们去书写,而现在市面上的手机大小不一(分辨率各不相同),一种适配所有手机的页面开发模式需求应由而生。(px 为一种固定的像素单位,不太适合需求),之后流式布局,响应式布局等随之产生,rem 的作用也逐渐凸显出来。

# 如何使用 rem+less 呢?

===> 新建个 less 目录,在里面做如下操作:

1. 新建 variable.less(名字随便都可以,反正这是一个表示变量的 less 文件)

@charset "utf-8";
//适配主流设备
@adapterDeviceList:750px,720px,640px,540px,529px,480px,434px,414px,400px,384px,375px,360px,320px;
//设计稿尺寸
@psdwidth:529px;  //就是你参考的设计稿的尺寸
/*
    预设基准值
    我习惯设100px,这样感觉用起来比较方便。比如:32px可以写作32rem/@baseFontSize
*/
@baseFontSize:100px;

//设备种类数量
@len:length(@adapterDeviceList);

2. 新建 mixins.less(这是一个表示函数的 less 文件)

/*
  这类似一个循环(定义一个函数),只是less没有跟js差不多的for循环啥滴,所以只能通过这种方式来实现一个循环。
*/
.adapterMixin(@index) when (@index > 0){
  @media (min-width: extract(@adapterDeviceList,@index)){
    html{
      font-size: @baseFontSize/@psdwidth* extract(@adapterDeviceList,@index);
    }
  }
  .adapterMixin(@index - 1);
}

3. 新建 adapter.less(调用函数)

.adapterMixin(@len);

4. 新建 index.less (主入口)

@charset "utf-8";
@import 'variable';
@import "mixins";
@import "adapter";

5. 在网页中引用

<link rel="stylesheet" type="text/less" href="/less/index.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.9.0/less.min.js"></script>

less 官网

说明:在网页中直接引用 less 文件是不行的,一定要加一个 less.min.js 来解析 less 文件,这样浏览器才能认识。

在完成上述操作后,你已基本完成 rem+less 的适配方式。接下来在 less 文件中 (像素单位 px 将可以用 rem/@baseFontSize 来代替),你的页面将适配所有大小的容器。

# 组件化思想

# 需求分析:

随着要写大量的页面,页面的重复,冗杂等问题相应而出。为了解决这种重复的问题,组件化思想出来了。

# 什么是组件化

组件化并不是前端所特有的,一些其他的语言或者桌面程序等,都具有组件化的先例。确切的说,只要有 UI 层的展示,就必定有可以组件化的地方。简单来说,组件就是将一段 UI 样式和其对应的功能作为独立的整体去看待,无论这个整体放在哪里去使用,它都具有一样的功能和样式,从而实现复用,这种整体化的细想就是组件化。不难看出,组件化设计就是为了增加复用性,灵活性,提高系统设计,从而提高开发效率。

  • css 实现代码分离(组件化思想):可以用 less,Sass,stylus。less 官网
  • html 实现代码分离(组件化思想):可以用模板引擎 ---- 如 art-template 等…

art-template 是一个简约、超快的模板引擎。它采用作用域预声明的技术来优化模板渲染速度,从而获得接近 JavaScript 极限的运行性能,并且同时支持 NodeJS 和浏览器。

  1. 拥有接近 JavaScript 渲染极限的的性能
  2. 调试友好:语法、运行时错误日志精确到模板所在行;支持在模板文件上打断点(Webpack Loader)
  3. 支持 Express、Koa、Webpack
  4. 支持模板继承与子模板
  5. 浏览器版本仅 6KB 大小

详情介绍: art-template 官网

# 总结

  1. 1. 适配技巧和组件化思想是你必不可少的技能
  2. 2. 组件化思想将是未来主流方向(React、Vue、Angular 三大前端主流框架)
  3. 3. 多做项目 ===> 体会这种组件化开发思想和适配方案。

解决 mongodb 取出时是 UTC 时间问题

# 解决 mongodb 取出时是 UTC 时间问题。

# 问题描述

# 问题:将一个时间类型数据保存到 mongodb 数据库中,在数据库中时间还是正常的时间,如:

mark

但是后台拿出来的时候却是这样的(node.js)

mark

解决方案:

网上查阅了很多资料,可我没找到一个解决方案(可能我比较傻吧),我只有自己想解决方案。

# 我的解决步骤:

# 1. 将 UTC 时间转换为 data 类型时间

/*publish在这里是一个数组,数组里面的每一项都是一个对象。 
  比如:publish[0].publishDate = 2019-03-15T08:44:07.842Z
*/
/*遍历publish数组*/
publish.forEach(function (e) {
  console.log(new Date(e.publishDate).toLocaleString());
});

结果:

mark

瞬间特别开心,以为解决了,谁知?(哎!)

# 2. 我开始将转变后的时间赋给原对象:

/*遍历publish数组*/
publish.forEach(function (e) {
  e.publishDate = new Date(e.publishDate).toLocaleString();
  console.log(e.publishDate);
});

结果:

mark

我百思不得其解,我也不知道为什么会这样,我想不可能啊!

于是:我想方设法查明其中的原有,最终我发现了一个问题:

console.log(typeof publish[0].publishDate); //object
console.log(typeof new Date(publish[0].publishDate).toLocaleString()); //string

原来是类型不一样,怪不得不能直接赋值,我何不把它们转换成一样的类型,然后进行赋值呢,于是,我有进行了下面的操作:

publish.forEach(function (e) {
  e.publishDate = JSON.parse(new Date(e.publishDate).toLocaleString());
  console.log(e.publishDate);
});

但结果报错了:

mark

# 3. 在我无限困惑的时候:我终于想到了一种可行的解决方案 ===>

# 我给 publish 新加了一个属性值:

mark

然后在代码中

publish.forEach(function (e) {
  e.UTCtodata = new Date(e.publishDate).toLocaleString();
  console.log(e.UTCtodata);
});

结果:

mark

# 渲染到页面:

<span class="list_time_submit">{{publish[i].UTCtodata}}</span>

页面效果:

mark

这就是我解决 mongodb 取出时间是 UTC 时间的解决办法,如果你们有特别好,特别简单的处理办法,可一定要告诉我哦!

关于我的博客

# 关于我的博客

我在写的过程中遇到的问题以及相应的解决办法:

# 1. 侧边栏固定问题

​ 问题:因为我做的博客主要适配移动端,不是 pc 端,pc 端的侧边栏固定应该是很简单的,如下代码就行:

position: fixed; top: 0; left: 0;

因为 position: fixed 属性总是相对于浏览器窗口来对元素进行定位。 而我想随着浏览器窗口的缩小,让我移动端的侧边栏总是固定有效视口的左上角,说说我的解决方案,我是用 js 控制的 (一觉醒来突然想通了,想想我为什么不用 js 解决呢)

let sideBar_Position = function () {
  let Width = window.innerWidth;
  if (Width > 900) {
    $(".sidebar").css({ left: (Width - 750) / 2 - 10 });
  }
  window.addEventListener("resize", function () {
    let innerWidth = window.innerWidth;
    if (innerWidth <= 772) {
      $(".sidebar").css({ left: 0 });
    } else {
      $(".sidebar").css({ left: (innerWidth - 750) / 2 - 10 });
    }
  });
};

效果:![侧边栏位置固定]

mark

# 2. 侧边栏消失问题

我想我的侧边栏应该有 2 种消失方案:1. 点击消失

​ 2. 滑动消失

解决方案:

  1. 点击消失 ==> 准备就用 jquery 的 show (), 和 hide () , 就弄简单点。
  2. 滑动消失 ==>
$(".sidebar").on("touchstart", function (e) {
  startX = e.touches[0].clientX;
});

$(".sidebar").on("touchmove", function (e) {
  moveX = e.touches[0].clientX;
  distanceX = startX - moveX;
  if (distanceX > 0) {
    settanslateX(-distanceX);
    isMove = true;
  } else {
    distanceX = 0;
  }
});

$(".sidebar").on("touchend", function (e) {
  if (isMove) {
    if (distanceX < ($(".sidebar>.sidebar-main").width() * 2) / 3) {
      addTranslation();
      settanslateX(0);
    } else {
      settanslateX(-$(".sidebar").width());
      addTranslation();
      $(".sidebar").css({
        display: "none",
        transition: "width 2s,left 2s",
        transform: "none",
      });
    }
  }
});

问题:可是写完之后发现了一个问题,当用滑动消失侧边栏后,再一次打开侧边栏,点击事件失效了(我一直没还搞懂,求懂滴大神指点指点)。

# 3. 列表动态跳转问题,列表跳转和分类列表跳转冲突问题(node.js),

–解决方案:

router.get("/:docName", function (req, res, next) {
  let docId = req.params.docName.replace(/"/g, "");
  let p = /[0-9]/;
  let b = p.test(docId); //true,说明有数字
  if (b) {
    publish.findById(docId, function (err, publish) {
      if (err) {
        return next(err);
      }
      if (publish.wholepublishIdentifying == "代码") {
        fs.readFile(
          __dirname + src + publish.publishMainBodyUrl + ".md",
          "utf-8",
          function (err, data) {
            if (err) {
              console.log(err);
            } else {
              htmlStr = marked(data.toString());
              res.type("html");
              message.find(
                {
                  message_type: publish.publishMainBodyUrl,
                },
                function (err, message) {
                  if (err) {
                    return next(err);
                  }
                  message.forEach(function (e) {
                    e.UTCtodata = new Date(e.message_time).toLocaleString();
                  });
                  res.render("MainBody.html", {
                    doc: htmlStr,
                    publish: publish,
                    message: message,
                  });
                }
              );
            }
          }
        );
      }
      if (publish.wholepublishIdentifying == "心得体会") {
        fs.readFile(
          __dirname + src + publish.publishMainBodyUrl + ".md",
          "utf-8",
          function (err, data) {
            if (err) {
              console.log(err);
            } else {
              htmlStr = marked(data.toString());
              res.type("html");
              message.find(
                {
                  message_type: publish.publishMainBodyUrl,
                },
                function (err, message) {
                  if (err) {
                    return next(err);
                  }
                  message.forEach(function (e) {
                    e.UTCtodata = new Date(e.message_time).toLocaleString();
                  });
                  res.render("MainBody.html", {
                    doc: htmlStr,
                    publish: publish,
                    message: message,
                  });
                }
              );
            }
          }
        );
      }
    });
  } else {
    publish.find(
      {
        publishIdentifying: req.params.docName,
      },
      function (err, publish) {
        if (err) {
          return next(err);
        }
        res.render("sortlayout.html", {
          publish: publish,
        });
      }
    );
  }
});

# 4:UTC 时间问题

问题:将时间类型数据保存到 mongodb 数据库中,拿出来时发现时间变成 类似于:2019-03-15T08:44:07.842Z — 这种 UTC 时间,这是 mongodb 数据库本身就存在的问题,自己遇到这个问题的时候,百度了很多文档,参考了很多人的解决办法,但还是不知道怎么解决,

最终好不容易想到了一种解决方案:

# mark

mark

有人会说为什么不把转变好的时间赋给原来的 UTC 时间属性,我一开始就这样写的,可是就是赋值不上去,

最终终于发现原因:因为一个是字符串,一个是对象,根本无法相互赋值。我随后也想过把对象转变为字符串然后进行赋值,可最终还是不行。无奈之下,我只好转换了思路,用了我一开始的方案,把问题解决了。

  1. # 分页效果(我参考了网上的做法 ----- 这里是全部加载完成后做的假分页)

    解决方案:

    html

    <div id="pageBox">
      <span id="prev">上一页</span>
      <ul id="pageNav"></ul>
      <span id="next">下一页</span>
    </div>

    css:那你自己写把。加油!

    js

    $(function () {
      tabPage({
        pageMain: "#pageMain",
        pageNav: "#pageNav",
        pagePrev: "#prev",
        pageNext: "#next",
        curNum: 4 /*每页显示的条数*/,
        activeClass: "active" /*高亮显示的class*/,
        ini: 0 /*初始化显示的页面*/,
      });
      function tabPage(tabPage) {
        var pageMain = $(tabPage.pageMain);
        /*获取内容列表*/
        var pageNav = $(tabPage.pageNav);
        /*获取分页*/
        var pagePrev = $(tabPage.pagePrev);
        /*上一页*/
        var pageNext = $(tabPage.pageNext);
        /*下一页*/
        var curNum = tabPage.curNum;
        /*每页显示数*/
        var len = Math.ceil(pageMain.find("li").length / curNum);
        /*计算总页数*/
        console.log(len);
        var pageList = "";
        /*生成页码*/
        var iNum = 0;
        /*当前的索引值*/
    
        for (var i = 0; i < len; i++) {
          pageList += '<a href="javascript:;">' + (i + 1) + "</a>";
        }
        pageNav.html(pageList);
        /*头一页加高亮显示*/
        pageNav.find("a:first").addClass(tabPage.activeClass);
    
        /*******标签页的点击事件*******/
        pageNav.find("a").each(function () {
          $(this).click(function () {
            pageNav.find("a").removeClass(tabPage.activeClass);
            $(this).addClass(tabPage.activeClass);
            iNum = $(this).index();
            $(pageMain).find("li").hide();
            for (
              var i = ($(this).html() - 1) * curNum;
              i < $(this).html() * curNum;
              i++
            ) {
              $(pageMain).find("li").eq(i).show();
            }
          });
        });
        $(pageMain).find("li").hide();
        /************首页的显示*********/
        for (var i = 0; i < curNum; i++) {
          $(pageMain).find("li").eq(i).show();
        }
        /*下一页*/
        pageNext.click(function () {
          $(pageMain).find("li").hide();
          if (iNum == len - 1) {
            alert("已经是最后一页");
            for (var i = (len - 1) * curNum; i < len * curNum; i++) {
              $(pageMain).find("li").eq(i).show();
            }
            return false;
          } else {
            pageNav.find("a").removeClass(tabPage.activeClass);
            iNum++;
            pageNav.find("a").eq(iNum).addClass(tabPage.activeClass);
            //                    ini(iNum);
          }
          for (var i = iNum * curNum; i < (iNum + 1) * curNum; i++) {
            $(pageMain).find("li").eq(i).show();
          }
        });
        /*上一页*/
        pagePrev.click(function () {
          $(pageMain).find("li").hide();
          if (iNum == 0) {
            alert("当前是第一页");
            for (var i = 0; i < curNum; i++) {
              $(pageMain).find("li").eq(i).show();
            }
            return false;
          } else {
            pageNav.find("a").removeClass(tabPage.activeClass);
            iNum--;
            pageNav.find("a").eq(iNum).addClass(tabPage.activeClass);
          }
          for (var i = iNum * curNum; i < (iNum + 1) * curNum; i++) {
            $(pageMain).find("li").eq(i).show();
          }
        });
      }
    });

    效果:

    mark

当然我还遇到很多别的问题,一时间都记不起来了(之后在慢慢加上去),所以写博客的重要性就在于此了。

MarkdownToHtml

# MarkdownToHtml

将 Markdown 文档转换为 HTML 显示

# 说明

本应用是采用 node.js + Express 搭建的

运用的模板:art-template

# 准备工作

我把 MarkdownToHTML.md 放在目录 public/doc 下(放在那里看你心情咯!)

# 安装 marked

npm install marked --save

# 关键步骤

路由部分关键代码:router.js ( 里面的部分代码是关键 )

src

router.get("/:docName", function (req, res, next) {
    docId = req.params.docName.replace(/"/g, '')
    publish.findById(docId, function (err, publish) {
        if (err) {
            return next(err)
        }
        fs.readFile(__dirname + src + publish.publishMainBodyUrl + '.md',           'utf-8', function (err, data) {
            if (err) {
                console.log(err);
            } else {
                htmlStr = marked(data.toString());
                res.type('html')
                message.find({
                    message_type: publish.publishMainBodyUrl
                }, function (err, message) {
                    if (err) {
                        return next(err)
                    }
                    message.forEach(function (e) {
                        e.UTCtodata = new Date(e.message_time).toLocaleString()
                    })
                    res.render('MainBody.html', {
                        doc: htmlStr,
                        publish: publish,
                        message: message
                    });
                })
            }
        });
    })
})

#

MainBody.html: 用 art-template 模板渲染后台传来的数据

<!--
   {{@ doc }}或者  <%- doc %>
 ( @和- 很关键 ==>原文输出语句不会对 HTML 内容进行转义处理,可能存在安全风险,请谨慎使用。这个坑害我多走了好多弯路。)
-->
<div id="markfs">
    {{@ doc }} <!-- 或者  <%- doc %> -->
</div>

# 效果展示

g

  • Copyrights © 2015-2021 zhou chen
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信