[Laravel5.4+自身集成Vue2初体验–续]laravel5.4的laravel-mix踩坑记

Laravel5.4 其实坑不少、这里说明一下

第一坑:cross-env目录不对

编译的时候会报错:node_modules/cross-env/bin/cross-env.js: No such file or directory

修改方案是修改package.json下面的node_modules/cross-env/bin/cross-env.js为node_modules/cross-env/dist/bin/cross-env.js  目录名称写错了

第二坑:laravel-mix版本太低

fallbackLoader option has been deprecated – replace with “fallback”
loader option has been deprecated – replace with “use”
Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
– configuration.output.path: The provided value “public” is not an absolute path!

要把package.json里面laravel-mix版本改成

“laravel-mix”: “^0.10.0”,

然后再执行 npm install

第三坑:X-CSRF-TOKEN问题

第一次使用,通常会遇到一个X-CSRF-TOKEN的错误,编译完成,前端页面启动过程抛异常

Uncaught TypeError: Cannot read property ‘csrfToken’ of undefined
at Object.<anonymous> (app.js:40921)
at __webpack_require__ (app.js:20)
at Object.<anonymous> (app.js:11198)
at __webpack_require__ (app.js:20)
at Object.<anonymous> (app.js:40943)
at __webpack_require__ (app.js:20)
at app.js:66
at app.js:69

查看编译后的app.js,发现有一段对X-CSRF-TOKEN的处理,默认是从window.Laravel中获取

window.axios.defaults.headers.common = {
 'X-CSRF-TOKEN': window.Laravel.csrfToken,
 // 'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
 'X-Requested-With': 'XMLHttpRequest'
};

这个变量没有设置,因此报错。

顺藤摸瓜,查源头,入口文件app.js 引用了一个资源文件 resources/assets/js/bootstrap.js,其中对X-CSRF-TOKEN有定义

window.axios = require('axios');

window.axios.defaults.headers.common = {
    'X-CSRF-TOKEN': window.Laravel.csrfToken,
    'X-Requested-With': 'XMLHttpRequest'
};

解决方案:

因为很多时候中间件也会检查CSRF-TOKEN,所以通常我们都习惯在模板文件中设置meta标记来保存CSRF-TOKEN,因此从这里统一获取,处理方式一致

<meta name=csrf-token content={{ csrf_token() }}>

因此,修改bootstrap.js对应代码为:

window.axios = require('axios'); window.axios.defaults.headers.common = {
 'X-CSRF-TOKEN':document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 
 'X-Requested-With': 'XMLHttpRequest' };

VueTP_前后端通用管理框架

VueTP是一套基于Vue2.x + iview + axios+ Thinkphp5的前后端通用管理自适应框架^_^

实现了一般前端后台所需要的功能模块,出发目的是以学习vue2和架构thinkphp框架

thinkphp后端采用restful接口风格,前端主要采用vue.js,是thinkphp5和vue的结合产物

目前分为俩个端Admin端和User端

主要适用技术栈

  • 后端框架:ThinkPHP 5.x
  • 前端MVVM框架:Vue.JS 2.x
  • 数据交互:Axios
  • UI框架:iview

本开源项目仅供大家学习学习和参考。

 

 

[thinkphp5]volist标签判断循环奇偶条数输出

这个判断奇偶条数经常在一些特殊的样式时用到,这里分享俩种方法:

1.用默认得mod属性,输出偶数记录

<volist name="data" id="item"  mod="2" >
   <eq name="mod" value="1">
      //偶数记录添加class even
      <li class="car-info-item even">
      <else/>
      <li class="car-info-item">
   </eq>
</volist>

2.用默认循环变量$i,输出偶数记录

<volist name="data" id="item"  mod="2" >
   <if condition="$i%2==0">
      <li class="car-info-item even">
      <else/>
      <li class="car-info-item">
   </if>
</volist>

下拉加载刷新thinkphp代码设计(防游品味)

具体demo这里就不提供了,具体效果可以去游品味上看,只说一下设计原理,大家将就看一下。

代码中的下一页和总页码都是后台计算得到的。

首先是JS代码如下:

<script>
   $(function(){
      //数据是否在加载中
      var isLoading = false;
      //加载次数
      var count = 0;
      //滚动加载次数
      var scrollCount = 2;
      //检测
      function loadMore(){
         $(window).scroll(function(e){
            //只需滚动加载5次
            if(count > scrollCount) return;

            var domH = $(document).height();
            var sTop = $(document.body).scrollTop();
            var h = $(window).height();
            if(domH < (sTop + h + 300)){
               loadMoreGame();
            }
         });
      }

      //加载更多游戏
      function loadMoreGame(){
         //如果正在加载中,则返回
         if(isLoading) return;
         isLoading = true;
         var $loadMore = $("#loadMore");
         var url = $loadMore.attr("next-page");

         var next = $loadMore.attr("next");//获取下一页
         var pagenum = $loadMore.attr("pagenum");//总页码
         
         if(parseInt(next)>parseInt(pagenum)){
            $(".loading").text("没有了");
            return;
         }

         $.ajax({
            url:url,
            success:function(result){
               if(result){
                  var $obj = $("<div>"+result+"</div>");
                  $obj.find(".section-bd .evaluate-list .item").appendTo($(".evaluate-list"));
                  var nurl = $obj.find(".ypw-load-more").attr("next-page");
                  //设置下一页的url
                  $loadMore.attr("next-page",nurl);

                  var next = $obj.find(".ypw-load-more").attr("next");
                  $loadMore.attr("next",next);


                  isLoading = false;
                  //加载次数增加一次
                  count ++;
                  if(count > scrollCount){
                     $loadMore.find(".loading").hide();
                     //大于5次则点击加载
                     $loadMore.find(".load").show().click(function(){
                        $loadMore.find(".loading").show();
                        $(this).hide();
                        //加载更多游戏
                        loadMoreGame();
                     });
                  }
               }
            }
         });
      }
   })
</script>

html代码大致如下:

   <div class="section-bd">
     <ul class="list evaluate-list">
            <volist name="data" id="item">
   <li class="item">
      <div class="evaluate-sub-pic">
         <img src="/static/wap_new/images/avatar.png" alt="" class="evaluate-avatar">
      </div>
      <div class="evaluate-sub-desc">
         <div class="evaluate-header">
            <h3 class="evaluate-name">{fy_$item.username}</h3>
            <div class="evaluate-view">
               <i class="icon icon-eye"></i> {fy_$item.fpclick}
            </div>
            <small class="evaluate-time">{fy_$item.fpcreatetime|date="Y-m-d h:i",###}</small>
         </div>
         <div class="evaluate-body">
            <h5 class="comment-title"><a style="font-size: .3rem;" href="/home/forum/detail/id/{fy_$item.fpid}">{fy_$item.fptitle}</a></h5>
            <div class="comment">
               {fy_$item.fpcontent|strip_tags|iconv_substr=0,60,'utf-8'}
            </div>
         </div>
         <div class="evaluate-footer">
             <ul class="group-link">
                <li class="link link-divider">
                     <a href="#">
                        <i class="icon icon-comment"></i>
                        {fy_$item.frnum}
                     </a>
                </li>
                <li class="link">
                   <a href="#">
                      <i class="icon icon-like"></i>
                      {fy_$item.fpclick}
                   </a>
                </li>
             </ul>
         </div>
      </div>
   </li>
            </volist>
</ul>
    <div  class="ypw-load-more" pagenum="{fy_$pagenum}" next="{fy_$next}" id="loadMore" next-page="/home/forum/forum_list?p={fy_$next}">
     <div class="loading" style="display: none;" >
      正在加载 请稍后···
     </div>
     <div class="load" style="display: none;">
      <span>点击加载更多</span>
     </div>
    </div>
    <!-- /.evaluate-list -->
   </div>

接口返回代码设计:

<div class="section-bd">
<ul class="list evaluate-list">
   <volist name="data" id="item">
      <li class="item">
         <div class="evaluate-sub-pic">
            <img src="/static/wap_new/images/avatar.png" alt="" class="evaluate-avatar">
         </div>
         <div class="evaluate-sub-desc">
            <div class="evaluate-header">
               <h3 class="evaluate-name">{fy_$item.username}</h3>
               <div class="evaluate-view">
                  <i class="icon icon-eye"></i> {fy_$item.fpclick}
               </div>
               <small class="evaluate-time">{fy_$item.fpcreatetime|date="Y-m-d h:i",###}</small>
            </div>
            <div class="evaluate-body">
               <h5 class="comment-title"><a style="font-size: .3rem;" href="/home/forum/detail/id/{fy_$item.fpid}">{fy_$item.fptitle}</a></h5>
               <div class="comment">
                  {fy_$item.fpcontent|strip_tags|iconv_substr=0,60,'utf-8'}
               </div>
            </div>
            <div class="evaluate-footer">
               <ul class="group-link">
                  <li class="link link-divider">
                     <a href="#">
                        <i class="icon icon-comment"></i>
                        {fy_$item.frnum}
                     </a>
                  </li>
                  <li class="link">
                     <a href="#">
                        <i class="icon icon-like"></i>
                        {fy_$item.fpclick}
                     </a>
                  </li>
               </ul>
            </div>
         </div>
      </li>
   </volist>
   <div class="ypw-load-more" pagenum="{fy_$pagenum}" next="{fy_$next}" id="loadMore" next-page="/home/forum/forum_list?p={fy_$next}">
      <div class="loading" >
         正在加载 请稍后···
      </div>
   </div>
</ul>
</div>

thinkphp标签调用函数(截取字符去除html等)

在这做个记录。

{$item.article|strip_tags|mb_substr=0,60,'utf-8'}

编译后的php代码:

<?php  echo (mb_substr(strip_tags($item.article),0,60,'utf-8')); > 

注意函数的定义和使用顺序的对应关系,通常来说函数的第一个参数就是前面的变量或者前一个函数使用的结果,如果你的变量并不是函数的第一个参数,需要使用定位符号,例如:

{$item.createtime|date="Y-m-d",###}

在thinkphp中集成微信JS-SDK示例代码(非常详细)

1.这里使用的环境是thinkphp5.0.7

2.登录微信公众号后台设置JS安全域名,这一步不多说

3.下载JS-SDK官方demo

·地址:http://demo.open.weixin.qq.com/jssdk/sample.zip

下载后解压出来php版本,如下图所示:

 

 

 

 

 

 

4.开始动工

在你的tp5框架的的第三方接口扩展目录下(我这里是extend)里面建立文件夹,命名为org(为了标准),把这4个文件复制进去,不要忘记设置命名空间,如下图所示

 

 

 

 

 

 

 

 

 

 

 

 

因为tp路由的关系,所以我们要对JSSDK.php的内容进行改写。定义path私有属性,改写路径。代码如下

 

 

 

 

 

 

 

 

 

 

 

 

5.开始调用

完成上述操作之后,我们已经成功的将微信jssdk部署到我们的项目中。下面只需要在你的合适得控制器中调用即可,一般在基类中调用

 

 

 

 

 

最后在你的view视图中这样子调用,前提不要忘了引入weixinJS

wx.config({
   debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
   appId: '{fy_$signPackage.appId}', // 必填,公众号的唯一标识
   timestamp: '{fy_$signPackage.timestamp}', // 必填,生成签名的时间戳
   nonceStr: '{fy_$signPackage.nonceStr}', // 必填,生成签名的随机串
   signature: '{fy_$signPackage.signature}',// 必填,签名,见附录1
   jsApiList: ['onMenuShareAppMessage','onMenuShareTimeline'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function(){
   wx.ready(function () {
      // 1 判断当前版本是否支持指定 JS 接口,支持批量判断
      wx.checkJsApi({
         jsApiList: [
            'onMenuShareTimeline',
            'onMenuShareAppMessage'
         ],
      });
      var shareData = {
         title: '测试标题',
         desc: '测试描述',
         link: 'http://baidu.com',
         imgUrl: '/uploads/20161207/5848184c8ec68.jpg',
      };
      wx.onMenuShareAppMessage(shareData);
      wx.onMenuShareTimeline(shareData);
   });
})

 

Thinkphp5结合PHPMailer发送邮件(php发送邮件)

网上发送邮件的例子有很多,今天这篇文章主要是采用了tp5和结合PHPMailer实现的,也算是比较新的了。

php命名空间是在php5.3中引入的,也得到了大家的认可,有不太懂的可以自行去学习。

thinkphp呢,不用多说了吧。本文主要是用了目前最新的tp5。

PHPMailer是一个用于发送电子邮件的php函数包,网上也有许多下载,不做太多解释。

1.第一步 准备文件

我们需要用到其中俩个类文件class.phpmailer.php和class.smtp.php

QQ截图20160828132846

 

 

 

 

 

 

 

因为TP5的命名规范,更加简洁,所以这里我简单得对俩个文件改了一下名称Mail.php,Smtp.php

QQ截图20160828133159

 

 

 

 

 

 

 

 

 

如图所示。把他放到了我项目中的扩展里面,大家可自行根据自己的项目位置来放。

2.第二步 增加命名空间

因为默认这俩个文件是没有命名空间的  所以得我们自己手动加一下。我的命名是namespace org;

QQ截图20160828133550

 

 

 

3.第三步 引入使用

这个时候我们就基本可以直接使用了,下面代码大家自己根据情况而写。

首先我们在配置文件中加入配置项 config.php

1
2
3
4
5
6
7
8
9
// 配置邮件发送服务器
'MAIL_HOST' =>'smtp.163.com',//smtp服务器的名称
'MAIL_SMTPAUTH' =>TRUE, //启用smtp认证
'MAIL_USERNAME' =>'xxxxxx@163.com',//你的邮箱名
'MAIL_FROM' =>'xxxxxx@163.com',//发件人地址
'MAIL_FROMNAME'=>'姓名',//发件人姓名
'MAIL_PASSWORD' =>'xxxx',//密码  注意这里是邮箱授权码
'MAIL_CHARSET' =>'utf-8',//设置邮件编码
'MAIL_ISHTML' =>TRUE, // 是否HTML格式邮件

然后在公共类文件中加入方法 common.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 邮件发送函数
 */
function sendMail($to, $title, $content,$mail) {
    $mail->IsSMTP(); // 启用SMTP
    $mail->Host=C('MAIL_HOST'); //smtp服务器的名称(这里以QQ邮箱为例)
    $mail->SMTPAuth = C('MAIL_SMTPAUTH'); //启用smtp认证
    $mail->Username = C('MAIL_USERNAME'); //你的邮箱名
    $mail->Password = C('MAIL_PASSWORD') ; //邮箱密码
    $mail->From = C('MAIL_FROM'); //发件人地址(也就是你的邮箱地址)
    $mail->FromName = C('MAIL_FROMNAME'); //发件人姓名
    $mail->AddAddress($to,"尊敬的客户");
    $mail->WordWrap = 50; //设置每行字符长度
    $mail->IsHTML(C('MAIL_ISHTML')); // 是否HTML格式邮件
    $mail->CharSet=C('MAIL_CHARSET'); //设置邮件编码
    $mail->Subject =$title; //邮件主题
    $mail->Body = $content; //邮件内容
    $mail->AltBody = "这是一个纯文本的身体在非营利的HTML电子邮件客户端"; //邮件正文不支持HTML的备用显示
    return($mail->Send());
}

最后呢大家在自己需要调用的控制器中调用即可,可别忘了引入空间!

1
2
$m = new Mail();
sendMail('xxxxxx@qq.com','标题','内容',$m)

常见的错误原因

1.这里是需要你邮箱开启STMP服务的

登录你的邮箱手动开启STMP服务,这个服务默认是关闭的,一定要去邮箱->设置 里去手动开启,开启时要求你设置一个独立密码,这个密码就是配置文件中的密码。

2.有时候可能会发送成功,但是对方没有接受到邮件

这里有可能是在系统默认为了垃圾邮件,需要自己到垃圾箱中找一下,QQ邮箱经常的事。

 

最后说的是

这里我也只是跟大家说了一下我的怎么应用,你只需要理解即可,而实际的应用呢,是需要大家自己变更的。

Thinkphp中比较标签的用法(eq,equa等)

其实这些标签在TP官方手册中已经有了明确的说明介绍,我这里就简单说明举例一下。

比较标签(判断输出数据)包括(eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq)
闭合 非闭合标签
属性 name(必须):变量名
value(必须):要比较的值,支持变量

用法:

1
<比较标签 name="变量" value="值">内容

系统支持的比较标签以及所表示的含义分别是:

eq或者 equal 等于
neq 或者notequal 不等于
gt 大于
egt 大于等于
lt 小于
elt 小于等于
heq 恒等于
nheq 不恒等于

他们的用法基本是一致的,区别在于判断的条件不同。

例如,要求name变量的值等于value就输出,可以使用:

1
<eq name="name" value="value">value</eq>

或者

1
<equal name="name" value="value">value</equal>

也可以支持和else标签混合使用:

1
<eq name="name" value="value">相等<else/>不相等</eq>

当 name变量的值大于5就输出

1
<gt name="name" value="5">value</gt>

当name变量的值不小于5就输出

1
<egt name="name" value="5">value</egt>

比较标签中的变量可以支持对象的属性或者数组,甚至可以是系统变量:
举例说明:
当vo对象的属性(或者数组,或者自动判断)等于5就输出

1
<eq name="vo.name" value="5">{$vo.name}</eq>

当vo对象的属性等于5就输出

1
<eq name="vo:name" value="5">{$vo.name}</eq>

当$vo[‘name’]等于5就输出

1
<eq name="vo['name']" value="5">{$vo.name}</eq>

而且还可以支持对变量使用函数
当vo对象的属性值的字符串长度等于5就输出

1
<eq name="vo:name|strlen" value="5">{$vo.name}</eq>

变量名可以支持系统变量的方式,例如:

1
<eq name="Think.get.name" value="value">相等<else/>不相等</eq>

通常比较标签的值是一个字符串或者数字,如果需要使用变量,只需要在前面添加“$”标志:
当vo对象的属性等于$a就输出

1
<eq name="vo:name" value="$a">{$vo.name}</eq>

所有的比较标签可以统一使用compare标签(其实所有的比较标签都是compare标签的别名),例如:
当name变量的值等于5就输出

1
<compare name="name" value="5" type="eq">value</compare>

等效于

1
<eq name="name" value="5" >value</eq>

其中type属性的值就是上面列出的比较标签名称

Thinkphp中时间戳格式化

不管是从数据库里提取出来的时间戳还是自己在代码中获取的时间戳,想要在THINKPHP(以下简称TP)里格式化时间,其实并不难,也没啥新颖;

两种情景下的格式化方式:

情景一(控制器中):

和在原生PHP代码中格式化一样,使用date函数:

1
$time = date("Y-m-d", $time)

情景二(模板):

1
{$time|date='Y-m-d',###}

其中呢,#是占位符表示位置,date=’Y-m-d H:i:s’,### 表示在函数date的传递参数的位置第一个是Y-M-D 第二个就是###就是它本身了

具体呢 模板上的函数,大家可以参考一下手册